diff --git a/.gitignore b/.gitignore index 27c5aa31f3..b845b36520 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,8 @@ __pycache__ db.sqlite3 media/ -static/ tmp/ +/static/ # Node node_modules/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 336fd8bb9d..a0219eba2e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,5 +12,9 @@ "svgwrite", "WAGTAILADMIN", "wagtailcore" - ] + ], + "html.format.templating": true, + "files.associations": { + "*.html": "django-html" + } } diff --git a/docs/setup/administrators/machine-translations.md b/docs/setup/administrators/machine-translations.md index 533e3a8221..98de1dbbff 100644 --- a/docs/setup/administrators/machine-translations.md +++ b/docs/setup/administrators/machine-translations.md @@ -23,14 +23,42 @@ This requirements file will specifically attempt to install the CPU version of [ ## Installing languages -Argostranslate handles translations via it's own packages - ie. Arabic -> English translation would be one package, while English -> Arabic would be another. +Argostranslate handles translations via its own packages—e.g., Arabic → English translation is one package, while English → Arabic is another. -Installing/uninstalling these packages can be done with the management commands `install_languages`/`uninstall_languages` respectively, utilizing the format of _. For example, installing the Arabic -> English & French -> English packages would look like: +You can install/uninstall these packages using the management commands `install_languages` and `uninstall_languages`, respectively. The format for specifying a package is `_`. For example, to install the Arabic → English and French → English packages: ```bash python3 manage.py install_languages ar_en fr_en ``` +### Additional options + +The `install_languages` command supports several options for flexibility: + +- **Install all available packages:** + ```bash + python3 manage.py install_languages --all + ``` + > ⚠️ This may install many packages and consume significant disk space. + +- **Interactively select packages:** + ```bash + python3 manage.py install_languages --select + ``` + This will present a numbered list of available language packages for you to choose from. + +- **Skip confirmation prompts:** + ```bash + python3 manage.py install_languages ar_en --noinput + ``` + This will install the specified packages without asking for confirmation. + +You can combine these options as needed. For example, to interactively select packages and skip confirmation: + +```bash +python3 manage.py install_languages --select --noinput +``` + ## Enabling on the system To enable machine translations on an instance, the proper configuration variables need to be set. These can be found in the [configuration options](configuration.md#hypha-custom-settings) diff --git a/hypha/addressfield/static/address_form.js b/hypha/addressfield/static/address_form.js index ba5bcd086d..908f172fb9 100644 --- a/hypha/addressfield/static/address_form.js +++ b/hypha/addressfield/static/address_form.js @@ -26,7 +26,9 @@ }; function labelFor(field) { - return $('label[for="' + $(field).attr("id") + '"]'); + var fieldId = $(field).attr("id"); + var label = $('label[for="' + fieldId + '"]'); + return label; } function makeFieldNotRequired(field) { @@ -54,13 +56,11 @@ oldValidate.call(this, field, config); }; - var selectWrap = '
'; - // Hook into the select builder to update the display var oldConvertToSelect = $.fn.addressfield.convertToSelect; $.fn.addressfield.convertToSelect = function () { var $select = oldConvertToSelect.call(this); - $select.wrap(selectWrap); + $select.wrap('
'); return $select; }; @@ -73,19 +73,21 @@ }; $(document).ready(function formReady() { - $(".form div.address").each(function () { - $(".form div#" + this.id).addressfield({ + $(".form .address").each(function () { + var config = { json: "/static/addressfield.min.json", fields: { - country: ".country", - thoroughfare: ".thoroughfare", - premise: ".premise", - locality: ".locality", - localityname: ".localityname", - administrativearea: ".administrativearea", - postalcode: ".postalcode", + country: "[data-js-addressfield-name='country']", + thoroughfare: "[data-js-addressfield-name='thoroughfare']", + premise: "[data-js-addressfield-name='premise']", + locality: "[data-js-addressfield-name='locality']", + localityname: "[data-js-addressfield-name='localityname']", + administrativearea: + "[data-js-addressfield-name='administrativearea']", + postalcode: "[data-js-addressfield-name='postalcode'] ", }, - }); + }; + $(".form div#" + this.id).addressfield(config); }); }); })(jQuery); diff --git a/hypha/addressfield/templates/addressfield/widgets/nested_with_label.html b/hypha/addressfield/templates/addressfield/widgets/nested_with_label.html index dd58bc2805..c86f9abfe9 100644 --- a/hypha/addressfield/templates/addressfield/widgets/nested_with_label.html +++ b/hypha/addressfield/templates/addressfield/widgets/nested_with_label.html @@ -1,8 +1,8 @@ -
{% spaceless %} +
{% for widget in widget.subwidgets %} {% if not widget.subwidgets %} -
- +
+ {% endif %} {% include widget.template_name %} @@ -11,4 +11,4 @@
{% endif %} {% endfor %} -{% endspaceless %}
+
diff --git a/hypha/addressfield/widgets.py b/hypha/addressfield/widgets.py index 6794a67b42..45027da852 100644 --- a/hypha/addressfield/widgets.py +++ b/hypha/addressfield/widgets.py @@ -20,11 +20,11 @@ class KeepAttrsTextInput(KeepOwnAttrsWidget, forms.TextInput): pass -def classify(field): +def classify(field: str) -> str: return field.replace("_", "") -def display(field): +def display(field: str) -> str: return field.replace("_", " ").title() @@ -36,6 +36,7 @@ def __init__(self, *args, **kwargs): widget( attrs={ "class": classify(field), + "data-js-addressfield-name": classify(field), "required": False, "display": display(field), } @@ -95,6 +96,6 @@ class Media: def __init__(self, *args, **kwargs): attrs = kwargs.get("attrs", {}) - attrs["class"] = "address" + attrs["class"] = "address -mt-2" kwargs["attrs"] = attrs super().__init__(*args, **kwargs) diff --git a/hypha/apply/activity/templates/activity/include/activity_list.html b/hypha/apply/activity/templates/activity/include/activity_list.html index 92135f9280..0b16080534 100644 --- a/hypha/apply/activity/templates/activity/include/activity_list.html +++ b/hypha/apply/activity/templates/activity/include/activity_list.html @@ -1,9 +1,9 @@ {% load i18n %} -
-
+
+
-
+
{% for activity in activities %} {% if activity.type == "comment" %} {% include "activity/ui/activity-comment-item.html" with activity=activity %} @@ -15,12 +15,12 @@ {% if page.has_next %} Show more... {% endif %}
diff --git a/hypha/apply/activity/templates/activity/notifications.html b/hypha/apply/activity/templates/activity/notifications.html index 3eedb3a273..bdb0f3b536 100644 --- a/hypha/apply/activity/templates/activity/notifications.html +++ b/hypha/apply/activity/templates/activity/notifications.html @@ -2,39 +2,36 @@ {% load i18n activity_tags heroicons %} {% block title %}{% trans "Notifications" %}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "Notifications" %}{% endslot %} - {% slot sub_heading %} - {% if PROJECTS_ENABLED %} - {% trans "Activity feed across all applications and projects" %} - {% else %} - {% trans "Activity feed across all the applications" %} - {% endif %} - {% endslot %} - -
+ - {{ filter.form }} - - - {% endadminbar %} +
+ {{ filter.form }} + +
+
+ +{% endblock %} -
-
+{% block content %} +
+
-
+
{% for activity in object_list %} {% with activity|display_for:request.user as activity_text %} -
+
{% ifchanged activity.source.id %} -
+ {% endifchanged %} diff --git a/hypha/apply/activity/templates/activity/partial_comment_message.html b/hypha/apply/activity/templates/activity/partial_comment_message.html index 57cfebaf3b..dd2e3808b7 100644 --- a/hypha/apply/activity/templates/activity/partial_comment_message.html +++ b/hypha/apply/activity/templates/activity/partial_comment_message.html @@ -12,17 +12,11 @@ {% if attachments %} {% endif %} diff --git a/hypha/apply/activity/templates/activity/ui/activity-action-item.html b/hypha/apply/activity/templates/activity/ui/activity-action-item.html index 502ab76fdd..24624882dd 100644 --- a/hypha/apply/activity/templates/activity/ui/activity-action-item.html +++ b/hypha/apply/activity/templates/activity/ui/activity-action-item.html @@ -1,12 +1,12 @@ {% load i18n activity_tags heroicons %} {% with activity|display_for:request.user as activity_text %} -
+
-
-
+
+
{% if 'edit' in activity_text.lower %} {% heroicon_micro "pencil-square" class="inline" aria_hidden=true size=14 %} @@ -40,7 +40,7 @@ {% if not submission_title and activity|user_can_see_related:request.user %} {% with url=activity.related_object.get_absolute_url %} {% if url %} - + {% trans "View" %} {% endif %} diff --git a/hypha/apply/activity/templates/activity/ui/activity-comment-item.html b/hypha/apply/activity/templates/activity/ui/activity-comment-item.html index be4d370f59..5670004f4d 100644 --- a/hypha/apply/activity/templates/activity/ui/activity-comment-item.html +++ b/hypha/apply/activity/templates/activity/ui/activity-comment-item.html @@ -1,21 +1,21 @@ {% load i18n activity_tags nh3_tags markdown_tags submission_tags apply_tags heroicons users_tags %} -
+
{% with activity|display_activity_author:request.user as author_name %} -
-
+
+
-
-
+
{{ author_name }} @@ -41,12 +41,10 @@ >{{ activity.timestamp|date:"SHORT_DATETIME_FORMAT" }} - -
+
{% if not request.user.is_applicant %} - {% if request.user.is_apply_staff and activity.assigned_to %} @@ -74,9 +72,9 @@ hx-get="{% url 'activity:edit-comment' activity.id %}" hx-target="#text-comment-{{activity.id}}" title="Edit Comment" - class="inline-flex items-center p-0.5 rounded-md opacity-80 transition-all hover:bg-fuchsia-200 hover:opacity-100" + class="btn btn-sm btn-square btn-ghost" > - {% heroicon_micro "pencil-square" size=18 class="inline" aria_hidden=true %} + {% heroicon_micro "pencil-square" aria_hidden=true %} {% trans "Edit" %} {% endif %} @@ -93,15 +91,16 @@
{% if not submission_title and activity|user_can_see_related:request.user %} - + {% endif %} + {% endwith %} {% endif %}
diff --git a/hypha/apply/activity/templates/activity/ui/edit_comment_form.html b/hypha/apply/activity/templates/activity/ui/edit_comment_form.html index 294812d82f..7f4c13936e 100644 --- a/hypha/apply/activity/templates/activity/ui/edit_comment_form.html +++ b/hypha/apply/activity/templates/activity/ui/edit_comment_form.html @@ -9,21 +9,23 @@ class="form" > {% csrf_token %} -
-
+
+
+
- + -
+
+
-
- - +
+ +
- diff --git a/hypha/apply/activity/templatetags/activity_tags.py b/hypha/apply/activity/templatetags/activity_tags.py index 649db233c2..c3301aef00 100644 --- a/hypha/apply/activity/templatetags/activity_tags.py +++ b/hypha/apply/activity/templatetags/activity_tags.py @@ -2,6 +2,7 @@ from django import template from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist from django.template.defaultfilters import stringfilter from django.utils.translation import gettext_lazy as _ @@ -44,8 +45,12 @@ def display_activity_author(activity, user) -> str: ): return settings.ORG_LONG_NAME - if isinstance(activity.related_object, Review) and activity.source.user == user: - return _("Reviewer") + try: + if isinstance(activity.related_object, Review) and activity.source.user == user: + return _("Reviewer") + except (AttributeError, ObjectDoesNotExist): + # Handle case where related object or content type is missing + pass if ( settings.HIDE_IDENTITY_FROM_REVIEWERS diff --git a/hypha/apply/dashboard/templates/dashboard/applicant_dashboard.html b/hypha/apply/dashboard/templates/dashboard/applicant_dashboard.html index 30c5725555..bc90c1ae27 100644 --- a/hypha/apply/dashboard/templates/dashboard/applicant_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/applicant_dashboard.html @@ -4,112 +4,141 @@ {% block title %}{% trans "Dashboard" %}{% endblock %} -{% block content %} -
-
-
-

{% trans "My dashboard" %}

-

{% trans "An overview of active and past submissions and projects" %}

-
-
+{% block hero %} + + +
-

{% trans "Submit a new application" %}

-

{% trans "Apply now for our open rounds" %}

+

{% trans "Submit a new application" %}

+

{% trans "Apply now for our open rounds" %}

-
-
+ + +{% endblock %} -
+{% block content %} +
{% if my_tasks.count %} {% include "dashboard/includes/my-tasks.html" with mytasks=mytasks %} {% endif %} {% if my_submissions_exists %} -
-
-

{% trans "My submissions" %}

-
- -
- {% for dummy_item in per_section_items %} -
-
-
- {% endfor %} - +
+

{% trans "My submissions" %}

+
+
+ {% for dummy_item in per_section_items %} +
+
+
+ {% endfor %} +
-
+
{% endif %} {% if my_projects_exists %} -
-
-

{% trans "My projects" %}

-
-
- {% for dummy_item in per_section_items %} -
-
-
- {% endfor %} +
+

{% trans "My projects" %}

+
+
+ {% for dummy_item in per_section_items %} +
+
+
+ {% endfor %} +
-
+
{% endif %} {% if active_invoices.count %} -
-
-

{% trans "My active invoices" %}

-
- {% for invoice in active_invoices.data %} -
-
-
-

- +
+

{% trans "My active invoices" %}

+
+ {% for invoice in active_invoices.data %} +
+
+

+ {{ invoice.invoice_number }}

-

{% trans "Date added: " %} {{ invoice.requested_at }}

+

+ {% trans "Submitted" %} + + {{ invoice.requested_at|date:"SHORT_DATETIME_FORMAT" }} + +

-
-

{% if invoice.invoice_amount %}{{ invoice.invoice_amount | format_number_as_currency }}{% else %}-{% endif %}

-
-
+
{% display_invoice_table_status_for_user invoice.status request.user as invoice_status %} -
-
-

- {{ invoice_status }} -

-
+ + {{ invoice_status }} + +
+
+ + {% if invoice.invoice_amount %} + {{ invoice.invoice_amount | format_number_as_currency }} + {% else %} + - + {% endif %} +
-
- {% empty %} - {% trans "No active invoices" %} - {% endfor %} -
+ {% empty %} +
+ {% trans "No active invoices" %} +
+ {% endfor %} +

+
{% endif %} -
- {% if historical_submissions.count %} -
-

{% trans "Submission history" %}

- {% render_table historical_submissions.table %} -
- {% endif %} - - {% if historical_projects.count %} -
-

{% trans "Project history" %}

- {% render_table historical_projects.table %} -
- {% endif %} + {% if historical_submissions.count %} +
+

+ {% trans "Submission history" %} +

+
+ {% render_table historical_submissions.table %} +
+
+ {% endif %} + {% if historical_projects.count %} +
+

+ {% trans "Project history" %} +

+
+ {% render_table historical_projects.table %} +
+
+ {% endif %} +
{% endblock %} diff --git a/hypha/apply/dashboard/templates/dashboard/community_dashboard.html b/hypha/apply/dashboard/templates/dashboard/community_dashboard.html index ddfe95263f..ee32db164a 100644 --- a/hypha/apply/dashboard/templates/dashboard/community_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/community_dashboard.html @@ -4,24 +4,35 @@ {% block title %}{% trans "Dashboard" %}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "Dashboard" %}{% endslot %} - {% slot sub_heading %}{% trans "An overview of active and past submissions" %}{% endslot %} - -
-

{% trans "Submit a new application" %}

-

{% trans "Apply now for our open rounds" %}

- {% trans "Apply" %} -
- {% endadminbar %} - -
+{% block hero %} + + +
+
+

{% trans "Submit a new application" %}

+

{% trans "Apply now for our open rounds" %}

+
+ +
+
+
+{% endblock %} -
-

- {% trans "Community review submissions" %} {{ my_community_review_count }} +{% block content %} +
+
+

+ {% trans "Community review submissions" %} + + {{ my_community_review_count }} +

{% if my_community_review.data %} @@ -29,19 +40,25 @@

{% else %} {% trans "No submissions" %} {% endif %} -

+ {% if my_reviewed.count %} -
-

+
+

{% trans "Your previous reviews" %}

- {% include "submissions/partials/submissions-inline.html" with submissions=my_reviewed.objects row_layout="table" %} -

+ + + {% endif %} - diff --git a/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html index f425b3fd8b..b97e0bce6f 100644 --- a/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/contracting_dashboard.html @@ -4,30 +4,42 @@ {% block title %}{% trans "Dashboard" %}{% endblock %} -{% block content %} - {% adminbar %} - {% slot header %}{% trans "Dashboard" %}{% endslot %} - - {% if perms.wagtailadmin.access_admin %} - - {% heroicon_solid "cog-6-tooth" size=20 class="inline align-text-bottom me-1" aria_hidden=true %} - {% trans "Administration" %} - - {% endif %} - {% endadminbar %} - -
+{% block hero %} + + + {% if perms.wagtailadmin.access_admin %} + + {% heroicon_solid "cog-6-tooth" size=20 class="opacity-80" aria_hidden=true %} + {% trans "Administration" %} + + {% endif %} + + +{% endblock %} +{% block content %} +
{% if my_tasks.count %} {% include "dashboard/includes/my-tasks.html" with mytasks=mytasks %} {% endif %} - {% if paf_for_review.count %} -
-

{% trans "PAFs for review" %}

- {% render_table paf_for_review.table %} +
+

+ {% trans "PAFs for review" %} +

+
+ {% if paf_for_review.count %} + {% render_table paf_for_review.table %} + {% else %} +

+ {% trans "You don't have any PAFs for review right now" %} +

+ {% endif %}
- {% endif %} +
+ {% if projects_in_contracting.count %} {% include "dashboard/includes/projects_in_contracting.html" with projects_in_contracting=projects_in_contracting %} diff --git a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html index 48a49b52ee..6d5ba07de3 100644 --- a/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/finance_dashboard.html @@ -4,99 +4,103 @@ {% block title %}{% trans "Dashboard" %}{% endblock %} -{% block content %} - {% adminbar %} - {% slot header %}{% trans "Dashboard" %}{% endslot %} - - {% if perms.wagtailadmin.access_admin %} - - {% heroicon_solid "cog-6-tooth" size=20 class="inline align-text-bottom me-1" aria_hidden=true %} - {% trans "Administration" %} - - {% endif %} - {% endadminbar %} - -
+{% block hero %} + + + {% if perms.wagtailadmin.access_admin %} + + {% heroicon_solid "cog-6-tooth" size=20 class="opacity-80" aria_hidden=true %} + {% trans "Administration" %} + + {% endif %} + + +{% endblock %} +{% block content %} +
{% if my_tasks.count %} {% include "dashboard/includes/my-tasks.html" with mytasks=mytasks %} {% endif %} -
-
-

{% trans 'Invoices' %}

- -
+ aria-label="{% trans 'Active invoices' %}" + checked="checked" /> +
+ {% if active_invoices.count %} + {% render_table active_invoices.table %} + {% else %} + + {% trans "No active invoices" %} + + {% endif %} +
- {# Active invoices tab #} -
- {% if active_invoices.count %} - {% render_table active_invoices.table %} - {% else %} -
- {% trans "No Active Invoices" %} -
- {% endif %} -
+ +
+ {% if invoices_for_approval.count %} + {% render_table invoices_for_approval.table %} + {% else %} + + {% trans "No invoices for Approval " %} + + {% endif %} +
- {# Waiting for approval tab #} -
- {% if invoices_for_approval.count %} - {% render_table invoices_for_approval.table %} - {% else %} -
- {% trans "No Invoices for Approval " %} -
- {% endif %} + +
+ {% if invoices_to_convert.count %} + {% render_table invoices_to_convert.table %} + {% else %} + + {% trans "No invoices for conversion " %} + + {% endif %} +
+ - {# Waiting for conversion tab #} -
- {% if invoices_to_convert.count %} - {% render_table invoices_to_convert.table %} +
+

{% trans "PAFs for review" %}

+
+ {% if not paf_for_review.count %} + {% render_table paf_for_review.table %} {% else %} -
- {% trans "No Invoices for Conversion " %} -
+

+ {% trans "You don't have any PAFs for review right now" %} +

{% endif %}
- -
- - {% if paf_for_review.count %} -
-

{% trans "PAFs for review" %}

- {% render_table paf_for_review.table %} -
- {% endif %} +
{% endblock %} diff --git a/hypha/apply/dashboard/templates/dashboard/includes/my-tasks.html b/hypha/apply/dashboard/templates/dashboard/includes/my-tasks.html index 9113cb3ac7..604c3fadbc 100644 --- a/hypha/apply/dashboard/templates/dashboard/includes/my-tasks.html +++ b/hypha/apply/dashboard/templates/dashboard/includes/my-tasks.html @@ -1,8 +1,10 @@ {% load i18n %} -
+
{% if my_tasks.data %} -

{% trans "My tasks" %}

+

+ {% trans "My tasks" %} +

{% for task in my_tasks.data %} diff --git a/hypha/apply/dashboard/templates/dashboard/includes/project_status_bar.html b/hypha/apply/dashboard/templates/dashboard/includes/project_status_bar.html index a387b9073f..915dd778ff 100644 --- a/hypha/apply/dashboard/templates/dashboard/includes/project_status_bar.html +++ b/hypha/apply/dashboard/templates/dashboard/includes/project_status_bar.html @@ -1,19 +1,21 @@ {% load dashboard_statusbar_tags %} -
- {% for status, text in statuses %} - {% if forloop.counter0 == current_status_index %} - {% include "funds/includes/status_bar_item.html" with is_current=True is_complete=False label=text %} - {% elif forloop.counter0 < current_status_index %} - {% include "funds/includes/status_bar_item.html" with is_current=False is_complete=True label=text %} - {% else %} - {% include "funds/includes/status_bar_item.html" with is_current=False is_complete=False label=text %} - {% endif %} - {% endfor %} -
+
+ -
-
+
{{ current_status_name }}
-
+
diff --git a/hypha/apply/dashboard/templates/dashboard/includes/projects_in_contracting.html b/hypha/apply/dashboard/templates/dashboard/includes/projects_in_contracting.html index 050f375791..6da0887047 100644 --- a/hypha/apply/dashboard/templates/dashboard/includes/projects_in_contracting.html +++ b/hypha/apply/dashboard/templates/dashboard/includes/projects_in_contracting.html @@ -1,48 +1,49 @@ {% load render_table from django_tables2 %} {% load i18n %} -
-
-

- {% trans 'Projects in contracting' %} -

- -
+ aria-label="{% trans 'Waiting for contract' %}" + checked="checked" /> +
+ {% if projects_in_contracting.waiting_for_contract.count %} + {% render_table projects_in_contracting.waiting_for_contract.table %} + {% else %} + + {% trans "No project is waiting for contract" %} + + {% endif %} +
-
- {% if projects_in_contracting.waiting_for_contract.count %} - {% render_table projects_in_contracting.waiting_for_contract.table %} - {% else %} -
- {% trans "No project is waiting for contract" %} -
- {% endif %} -
-
- {% if projects_in_contracting.waiting_for_contract_approval.count %} - {% render_table projects_in_contracting.waiting_for_contract_approval.table %} - {% else %} -
- {% trans "No project is waiting for contract approval " %} -
- {% endif %} + +
+ {% if projects_in_contracting.waiting_for_contract_approval.count %} + {% render_table projects_in_contracting.waiting_for_contract_approval.table %} + {% else %} + + {% trans "No project is waiting for contract approval" %} + + {% endif %} +
- -
+
\ No newline at end of file diff --git a/hypha/apply/dashboard/templates/dashboard/includes/submissions-waiting-for-review.html b/hypha/apply/dashboard/templates/dashboard/includes/submissions-waiting-for-review.html index 32136e2e95..f7a2e6e692 100644 --- a/hypha/apply/dashboard/templates/dashboard/includes/submissions-waiting-for-review.html +++ b/hypha/apply/dashboard/templates/dashboard/includes/submissions-waiting-for-review.html @@ -1,27 +1,32 @@ -{% load render_table from django_tables2 %} {% load i18n %} -

- {% trans "Submissions waiting for your review" %} {{ in_review_count }} +

+ + {% trans "Submissions waiting for your review" %} + {{ in_review_count }} +

-{% if my_review.data %} - - {% include "submissions/partials/submissions-inline.html" with submissions=my_review.data row_layout="table" %} - {% comment %} {% render_table my_review %} {% endcomment %} - - {% if display_more %} - - {% endif %} - +{% if my_review %} + {% else %} -
-

{% trans "Nice! You're all caught up. 🎉" %}

- {% trans "Find new applications to review" %} +
+
+

+ {% trans "Nice! You're all caught up. 🎉" %}
+ {% trans "Find new applications to review" %} + +

+
- {# TODO Fill in data and update styles in future ticket #} -
{# Since you last logged in #}
- {% endif %} diff --git a/hypha/apply/dashboard/templates/dashboard/partials/applicant_projects.html b/hypha/apply/dashboard/templates/dashboard/partials/applicant_projects.html index 97d6cec881..40024a531f 100644 --- a/hypha/apply/dashboard/templates/dashboard/partials/applicant_projects.html +++ b/hypha/apply/dashboard/templates/dashboard/partials/applicant_projects.html @@ -1,33 +1,33 @@ {% load i18n dashboard_statusbar_tags statusbar_tags workflow_tags %} -{% for project in page.object_list %} -
-
-
-

{{ project.title }}

-

{% trans "Project start date: " %} {{ project.created_at.date }}

+
+ {% for project in page.object_list %} +
+
+

+ + {{ project.title }} + +

+

+ {% trans "Project started " %} {{ project.created_at.date }} +

- {% project_status_bar project.status request.user css_class="status-bar--small" %} -
-
-{% empty %} - {% trans "No active projects" %} -{% endfor %} - -
+ {% empty %} +
+ {% trans "No active projects" %} +
+ {% endfor %} +
- {% if page.has_next %} - - » - {% endif %} - - + diff --git a/hypha/apply/dashboard/templates/dashboard/partials/applicant_submissions.html b/hypha/apply/dashboard/templates/dashboard/partials/applicant_submissions.html index 517f0a7f5b..af173d9ff2 100644 --- a/hypha/apply/dashboard/templates/dashboard/partials/applicant_submissions.html +++ b/hypha/apply/dashboard/templates/dashboard/partials/applicant_submissions.html @@ -2,62 +2,80 @@ {% load can from permission_tags %} {% for submission in page.object_list %} -
-
-
-

- - {{ submission.title }} - #{{ submission.application_id }} - -

-

+

+
+

+ + {{ submission.title }} + #{{ submission.application_id }} + {% if submission.is_draft %} - {% trans "Drafted on " %} - {% else %} - {% trans "Submitted on " %} + {% trans "Draft" %} {% endif %} - {{ submission.submit_time.date }} {% trans "by" %} {{ submission.user.get_full_name }} -

+
+

+

+ {% if submission.is_draft %} + {% trans "Drafted" %} + {% else %} + {% trans "Submitted" %} + {% endif %} + + {{ submission.submit_time|date:'SHORT_DATETIME_FORMAT' }} + + {% if submission.user != request.user %} + {% trans "by" %} {{ submission.user.get_full_name }} + {% endif %} +

+ - {% status_bar submission.workflow submission.phase request.user css_class="status-bar--small" %} +
+ +
+ {% status_bar submission.workflow submission.phase request.user css_class="w-full" %}
{% empty %} - {% trans "No active submissions" %} +
+ {% trans "No active submissions" %} +
{% endfor %} - + target="#submissions_list" + class="my-4" + use_htmx +> diff --git a/hypha/apply/dashboard/templates/dashboard/partner_dashboard.html b/hypha/apply/dashboard/templates/dashboard/partner_dashboard.html index 030dc5d02f..d80f25a411 100644 --- a/hypha/apply/dashboard/templates/dashboard/partner_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/partner_dashboard.html @@ -4,61 +4,72 @@ {% block title %}{% trans "Dashboard" %}{% endblock %} -{% block content %} - - {% adminbar %} - - {% slot header %}{% trans "Dashboard" %}{% endslot %} - {% slot sub_heading %}{% trans "Welcome" %}, {{ request.user }}!{% endslot %} - - {% endadminbar %} +{% block hero %} + + + +{% endblock %} -
+{% block content %} +
-
-

- {% trans "You are the partner of these submissions" %} {{ partner_submissions_count }} -

+
+

+ {% trans "You are the partner of these submissions" %} {{ partner_submissions_count }} +

{% if partner_submissions.data %} - {% render_table partner_submissions %} +
+ {% render_table partner_submissions %} +
{% else %} {% trans "No submissions" %} {% endif %} -
+
-
-

{% trans "Your active submissions" %}

- {% for submission in my_submissions %} -
-
-
-
{{ submission.title_text_display }}
-
{% trans "Submitted" %}: {{ submission.submit_time.date }} {% trans "by" %} {{ submission.user.get_full_name }}
+
+

{% trans "Your active submissions" %}

+
+
+ {% for submission in my_submissions %} +
+
+
{{ submission.title_text_display }}
+
{% trans "Submitted" %}: {{ submission.submit_time.date }} {% trans "by" %} {{ submission.user.get_full_name }}
+
+ {% status_bar submission.workflow submission.phase request.user css_class="status-bar--small" %}
- {% status_bar submission.workflow submission.phase request.user css_class="status-bar--small" %} -
- {% if request.user|has_edit_perm:submission %} - - {% if submission.status == 'draft_proposal' %} - {% trans "Start your" %} {{ submission.stage }} {% trans "application" %} - {% else %} - {% trans "Edit" %} - {% endif %} - - {% endif %} + {% if request.user|has_edit_perm:submission %} + + {% if submission.status == 'draft_proposal' %} + {% trans "Start your" %} {{ submission.stage }} {% trans "application" %} + {% else %} + {% trans "Edit" %} + {% endif %} + + {% endif %} +
+ {% empty %} +

+ {% trans "No active submissions" %} +

+ {% endfor %}
- {% empty %} - {% trans "No active submissions" %} - {% endfor %} -
+
- {% if my_inactive_submissions.data %} -
-

{% trans "Submission history" %}

- {% render_table my_inactive_submissions %} -
- {% endif %} -
+ {% if my_inactive_submissions.data %} +
+

+ {% trans "Submission history" %} +

+
+ {% render_table my_inactive_submissions %} +
+
+ {% endif %} +
{% endblock %} diff --git a/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html b/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html index 0d9948d7c0..957d82dac2 100644 --- a/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/reviewer_dashboard.html @@ -4,64 +4,73 @@ {% block title %}{% trans "Dashboard" %}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "Dashboard" %}{% endslot %} - {% endadminbar %} - -
+{% block hero %} + + + +{% endblock %} -
- {% include "dashboard/includes/submissions-waiting-for-review.html" with in_review_count=awaiting_reviews.count my_review=awaiting_reviews.table display_more=awaiting_reviews.display_more active_statuses_filter=awaiting_reviews.active_statuses_filter %} -
+{% block content %} +
+
+ {% include "dashboard/includes/submissions-waiting-for-review.html" with in_review_count=awaiting_reviews.count my_review=awaiting_reviews.submissions display_more=awaiting_reviews.display_more %} +
{% if my_flagged.count %} -
-

- Your flagged submissions ({{ my_flagged.count }}) -

- - {% include "submissions/partials/submissions-inline.html" with submissions=my_flagged.objects row_layout="table" %} +
+

+ + {% trans "Your flagged submissions" %} + + {{ my_flagged.count }} + + +

- {% if my_flagged.display_more %} -
- Show All -
- {% endif %} -
+ + {% endif %} {% if my_reviewed.count %} -
-

{% trans "Your previous reviews" %} {{ my_reviewed.count }}

- - {% include "submissions/partials/submissions-inline.html" with submissions=my_reviewed.objects row_layout="table" %} - - {% if my_reviewed.display_more %} - - {% endif %} -
+
+

+ + {% trans "Your previous reviews" %} + {{ my_reviewed.count }} + +

+ +
{% endif %} {% if my_submissions %} -
-

+
+

{% trans "Your active submissions" %}

{% for submission in my_submissions %}
-
{{ submission.title }}
-
{% trans "Submitted" %}: {{ submission.submit_time.date }} {% trans "by" %} {{ submission.user.get_full_name }}
+
{{ submission.title }}
+
{% trans "Submitted" %}: {{ submission.submit_time.date }} {% trans "by" %} {{ submission.user.get_full_name }}
{% status_bar submission.workflow submission.phase request.user css_class="status-bar--small" %}
{% if request.user|has_edit_perm:submission %} - + {% if submission.status == 'draft_proposal' %} {% trans "Start your" %} {{ submission.stage }} {% trans "application" %} {% else %} @@ -71,17 +80,16 @@
{% trans " {% endif %}
{% endfor %} -

+ {% endif %} {% if my_inactive_submissions.data %} -
-

+
+

{% trans "Submission history" %}

{% render_table my_inactive_submissions %} -

+ {% endif %}
- {% endblock %} diff --git a/hypha/apply/dashboard/templates/dashboard/staff_dashboard.html b/hypha/apply/dashboard/templates/dashboard/staff_dashboard.html index aea8b64137..ab4b4c24ca 100644 --- a/hypha/apply/dashboard/templates/dashboard/staff_dashboard.html +++ b/hypha/apply/dashboard/templates/dashboard/staff_dashboard.html @@ -4,134 +4,150 @@ {% block title %}{% trans "Dashboard" %}{% endblock %} -{% block content %} - {% adminbar %} - {% slot header %}{% trans "Dashboard" %}{% endslot %} - {% slot sub_heading %}{% trans "Welcome" %}, {{ request.user }}!{% endslot %} - - {% if perms.wagtailadmin.access_admin %} - - {% heroicon_solid "cog-6-tooth" size=20 class="inline align-text-bottom me-1" aria_hidden=true %} - {% trans "Administration" %} - - {% endif %} - {% endadminbar %} +{% block hero %} + + + {% if perms.wagtailadmin.access_admin %} + + {% heroicon_solid "cog-6-tooth" size=20 class="opacity-80" aria_hidden=true %} + {% trans "Administration" %} + + {% endif %} + + +{% endblock %} + -
-
- {% if my_tasks.count %} +{% block content %} +
+ {% if my_tasks.count %} +
{% include "dashboard/includes/my-tasks.html" with mytasks=mytasks %} - {% endif %} +
+ {% endif %} - + -
- {% include "dashboard/includes/submissions-waiting-for-review.html" with in_review_count=awaiting_reviews.count my_review=awaiting_reviews.table display_more=awaiting_reviews.display_more active_statuses_filter=awaiting_reviews.active_statuses_filter %} -
+
+ {% include "dashboard/includes/submissions-waiting-for-review.html" with in_review_count=awaiting_reviews.count my_review=awaiting_reviews.submissions display_more=awaiting_reviews.display_more %} +
{% if my_flagged.count %} -
-

- Your flagged submissions {{ my_flagged.count }} -

- - {% include "submissions/partials/submissions-inline.html" with submissions=my_flagged.objects row_layout="table" %} - - {% if my_flagged.display_more %} -
- Show All -
- {% endif %} -
+
+

+ + Your flagged submissions {{ my_flagged.count }} + +

+ +
{% endif %} {% if rounds.closed or rounds.open %} - {% include "funds/includes/round-block.html" with can_export=can_export closed_rounds=rounds.closed open_rounds=rounds.open title="Your rounds and labs" page_type='dashboard' %} +
+ {% include "funds/includes/round-block.html" with can_export=can_export closed_rounds=rounds.closed open_rounds=rounds.open title="Your rounds and labs" page_type='dashboard' %} +
{% endif %} {% if PROJECTS_ENABLED and paf_for_review.count %} -
-

{% trans "Project forms for review" %}

- {% render_table paf_for_review.table %} -
+
+

{% trans "Project forms for review" %}

+
+ {% render_table paf_for_review.table %} +
+
{% endif %} {% if PROJECTS_ENABLED and projects.table.data %} -
-

- {% trans "Your projects" %} -

+
+

{% trans "Your projects" %}

- {% render_table projects.table %} +
+ {% render_table projects.table %} +
- +
{% endif %} {% if PROJECTS_ENABLED and active_invoices.count %} -
-

{% trans "Active Invoices" %}

- {% render_table active_invoices.table %} -
+
+

{% trans "Active invoices" %}

+ +
+ {% render_table active_invoices.table %} +
+
{% endif %} {% if my_reviewed.count %} -
-

{% trans "Your previous reviews" %} {{ my_reviewed.count }}

- {% include "submissions/partials/submissions-inline.html" with submissions=my_reviewed.objects row_layout="table" %} - - {% if my_reviewed.display_more %} - - {% endif %} -
+
+

+ + {% trans "Your previous reviews" %} {{ my_reviewed.count }} + +

+ + +
{% endif %} -
{% endblock %} - - -{% block extra_js %} - -{% endblock %} diff --git a/hypha/apply/dashboard/tests/test_views.py b/hypha/apply/dashboard/tests/test_views.py index 924dbfce7b..0394c2b609 100644 --- a/hypha/apply/dashboard/tests/test_views.py +++ b/hypha/apply/dashboard/tests/test_views.py @@ -118,13 +118,13 @@ def test_waiting_for_review_after_agreement_is_empty(self): def test_active_invoices_with_no_project(self): response = self.get_page() - self.assertNotContains(response, "Active Invoices") + self.assertNotContains(response, "Active invoices") def test_doesnt_show_active_invoices_with_none(self): ProjectFactory(lead=self.user) response = self.get_page() - self.assertNotContains(response, "Active Invoices") + self.assertNotContains(response, "Active invoices") def test_doest_show_active_invoices_when_paid_or_declined(self): project = ProjectFactory(lead=self.user) @@ -132,7 +132,7 @@ def test_doest_show_active_invoices_when_paid_or_declined(self): InvoiceFactory(project=project, status=DECLINED) response = self.get_page() - self.assertNotContains(response, "Active Invoices") + self.assertNotContains(response, "Active invoices") def test_active_invoices_with_invoices_in_correct_state(self): project = ProjectFactory(lead=self.user) @@ -141,7 +141,7 @@ def test_active_invoices_with_invoices_in_correct_state(self): InvoiceFactory(project=project, status=RESUBMITTED) response = self.get_page() - self.assertContains(response, "Active Invoices") + self.assertContains(response, "Active invoices") def test_doesnt_show_active_invoices_when_not_mine(self): project = ProjectFactory() @@ -150,7 +150,7 @@ def test_doesnt_show_active_invoices_when_not_mine(self): InvoiceFactory(project=project, status=RESUBMITTED) response = self.get_page() - self.assertNotContains(response, "Active Invoices") + self.assertNotContains(response, "Active invoices") def test_unassigned_staff_cant_see_projects_awaiting_review_stats_or_table(self): ProjectFactory(is_locked=False, status=INTERNAL_APPROVAL) diff --git a/hypha/apply/dashboard/views.py b/hypha/apply/dashboard/views.py index 324a4f7d48..a9405bfbff 100644 --- a/hypha/apply/dashboard/views.py +++ b/hypha/apply/dashboard/views.py @@ -15,8 +15,6 @@ from hypha.apply.funds.tables import ( ReviewerSubmissionsTable, SubmissionsTable, - SummarySubmissionsTableWithRole, - review_filter_for_user, ) from hypha.apply.projects.filters import ProjectListFilter from hypha.apply.projects.models import Invoice, Project, ProjectSettings @@ -133,15 +131,9 @@ def awaiting_reviews(self, submissions): limit = 5 return { - "active_statuses_filter": "".join( - f"&status={status}" - for status in review_filter_for_user(self.request.user) - ), "count": count, "display_more": count > limit, - "table": SummarySubmissionsTableWithRole( - submissions[:limit], prefix="my-review-" - ), + "submissions": submissions[:limit], } def active_invoices(self): @@ -304,13 +296,9 @@ def awaiting_reviews(self, submissions): limit = 5 return { - "active_statuses_filter": "".join( - f"&status={status}" - for status in review_filter_for_user(self.request.user) - ), "count": count, "display_more": count > limit, - "table": ReviewerSubmissionsTable(submissions[:limit], prefix="my-review-"), + "submissions": submissions[:limit], } @@ -515,6 +503,7 @@ def historical_submission_data(self): ) return { "count": historical_submissions.count(), + "submissions": historical_submissions, "table": SubmissionsTable(data=historical_submissions), } diff --git a/hypha/apply/determinations/templates/determinations/base_determination_form.html b/hypha/apply/determinations/templates/determinations/base_determination_form.html index 3429aae9e9..eb31ac9a48 100644 --- a/hypha/apply/determinations/templates/determinations/base_determination_form.html +++ b/hypha/apply/determinations/templates/determinations/base_determination_form.html @@ -1,88 +1,115 @@ {% extends "base-apply.html" %} -{% load i18n static nh3_tags %} +{% load i18n static nh3_tags heroicons %} {% block title %}{% if object %}{% trans "Edit a Determination" %} {% if object.is_draft %}{% trans "draft" %}{% endif %}{% else %}{% trans "Create a Determination" %}{% endif %}{% endblock %} +{% block body_attrs %}x-data="{ showSubmission: false }"{% endblock %} + +{% block hero %} + + + +
+
+ +
+
+
+
+{% endblock %} + {% block content %} + {% block form %} +
+
+ {% include "forms/includes/form_errors.html" with form=form %} + {% block determination_information %}{% endblock %} - {% block adminbar %} - {% adminbar %} - {% slot header %}{% if object %}{% trans "Update Determination draft" %}{% else %}{% trans "Create Determination" %}{% endif %}{% endslot %} - {% slot sub_heading %}{% if submission %}{% trans "For" %} {{ submission.title_text_display }}{% endif %}{% endslot %} - {% slot buttons %} - - - {% endslot %} - {% endadminbar %} - {% endblock %} + {% csrf_token %} + {% for hidden in form.hidden_fields %} + {{ hidden }} + {% endfor %} + {% for field in form.visible_fields %} + {# to be replaced with better logic when/if we use stream form #} + {% ifchanged field.field.group %} + {% for key, value in form.titles.items %} + {% if key == field.field.group %} +

{{ value }}

+ {% endif %} + {% endfor %} + {% endifchanged %} + {% if field.field %} + {% include "forms/includes/field.html" %} + {% else %} +
+
+ {{ field.block }} +
+
+ {% endif %} + {% endfor %} + {% block form_buttons %} +
+ - {% block form %} -
- {% include "forms/includes/form_errors.html" with form=form %} - {% block determination_information %} - {% endblock %} -
- {% csrf_token %} - {% for hidden in form.hidden_fields %} - {{ hidden }} - {% endfor %} - {% for field in form.visible_fields %} - {# to be replaced with better logic when/if we use stream form #} - {% ifchanged field.field.group %} - {% for key, value in form.titles.items %} - {% if key == field.field.group %} -

{{ value }}

+ {% if form.draft_button_name %} + {% endif %} - {% endfor %} - {% endifchanged %} - {% if field.field %} - {% include "forms/includes/field.html" %} - {% else %} -
- {{ field.block }}
- {% endif %} - {% endfor %} - {% block form_buttons %} -
- {% if form.draft_button_name %} - - {% endif %} - + {% endblock %} + + {% for type, message in message_templates.items %} + - {% endblock %} - - {% for type, message in message_templates.items %} - - {% endfor %} + {% endfor %} +
+ {% block show_submission %} -
{% endblock %} +
{% endblock %} {% endblock %} diff --git a/hypha/apply/determinations/templates/determinations/batch_determination_form.html b/hypha/apply/determinations/templates/determinations/batch_determination_form.html index 7da52103ab..d4e8f61240 100644 --- a/hypha/apply/determinations/templates/determinations/batch_determination_form.html +++ b/hypha/apply/determinations/templates/determinations/batch_determination_form.html @@ -5,31 +5,41 @@ {{ block.super }} {% endblock %} -{% block adminbar %} - {% adminbar %} - {% slot header %}{% trans "Add Batch Determination" %} - {{ action_name }}{% endslot %} - {% endadminbar %} +{% block hero %} + + + {% endblock %} {% block determination_information %} -
-
- {% trans "Determining" %} {{ submissions.count }} {% trans "submission" %}{{ submissions.count|pluralize }} {% trans "as" %} "{{ action_name }}" - {% trans "Show" %} +
+ + + {% trans "Determining" %} {{ submissions.count }} {% trans "submission" %}{{ submissions.count|pluralize }} {% trans "as" %} "{{ action_name }}" + + + - -
+ {% endblock %} {% block form_buttons %} - {% endblock %} diff --git a/hypha/apply/determinations/templates/determinations/determination_detail.html b/hypha/apply/determinations/templates/determinations/determination_detail.html index 1ef1c34869..64d7e57d66 100644 --- a/hypha/apply/determinations/templates/determinations/determination_detail.html +++ b/hypha/apply/determinations/templates/determinations/determination_detail.html @@ -1,47 +1,76 @@ {% extends "base-apply.html" %} -{% load i18n nh3_tags heroicons %} +{% load i18n nh3_tags heroicons apply_tags %} {% block title %}{% trans "Determination for" %} {{ determination.submission.title }}{% endblock %} +{% block hero %} + + + +{% endblock %} + + {% block content %} - {% adminbar %} - {% slot back_link %} - - {% trans "View application" %} - - {% endslot %} - - {% slot header %} {% trans "Determination" %} {% if determination.is_draft %}[{% trans "DRAFT" %}] {% endif %}{% endslot %} - {% slot sub_heading %} - {% trans "For" %} {{ determination.submission.title_text_display }} - {% endslot %} - - {% endadminbar %} - -
-
- {% trans "Determination" %}: {{ determination.get_outcome_display }} -
- {% if request.user.is_apply_staff %} - - - {% trans "Edit" %}{% heroicon_mini "pencil-square" size=18 class="inline align-text-bottom ms-1" aria_hidden=true %} - - - {% endif %} -
+
+
+
+
{% trans "Outcome" %}:
+
{{ determination.get_outcome_display }}
+
-
-

{% trans "Determination message" %}

- {{ determination.message|nh3 }} - {% for group in determination.detailed_data.values %} - {% if group.title %} -

{{ group.title|nh3 }}

+ + {% if request.user.is_apply_staff %} + + {% heroicon_mini "pencil-square" size=18 aria_hidden=true class="opacity-80 size-4" %} + {% if determination.is_draft %} + {% trans "Continue editing" %} + {% else %} + {% trans "Edit" %} + {% endif %} + {% endif %} - {% for question, answer in group.questions %} -
{{ question }}
- {% if answer %}{% if answer == True %}{{ answer|yesno:"Agree,Disagree" }}{% else %}{{ answer|nh3 }}{% endif %}{% else %}-{% endif %} - {% endfor %} +
+ +
+

+ {% trans "Determination message" %} +

+ +
+ {{ determination.message|nh3 }} +
+
+ + {% for group in determination.detailed_data.values %} +
+ {% if group.title %} +

{{ group.title|nh3 }}

+ {% endif %} + + {% for question, answer in group.questions %} +

{{ question }}

+ {% if answer %} + {% if answer == True or answer == False %} + {{ answer|yesno:"Agree,Disagree" }} + {% else %} +
+ {{ answer|nh3 }} +
+ {% endif %} + {% else %} + - + {% endif %} + {% endfor %} +
{% endfor %} +
{% endblock %} diff --git a/hypha/apply/determinations/templates/determinations/determination_form.html b/hypha/apply/determinations/templates/determinations/determination_form.html index 0d466cafea..d771dcafcd 100644 --- a/hypha/apply/determinations/templates/determinations/determination_form.html +++ b/hypha/apply/determinations/templates/determinations/determination_form.html @@ -1,9 +1,2 @@ {% extends "determinations/base_determination_form.html" %} {% load i18n %} - -{% adminbar %} - {% slot header %} - {% if object %}{% trans "Edit determination" %} {% if object.is_draft %}{% trans "draft" %}{% endif %}{% else %}{% trans "Create Determination" %}{% endif %} - {% endslot %} - {% slot sub_heading %}{% trans "For" %} {{ submission.title_text_display }}{% endslot %} -{% endadminbar %} diff --git a/hypha/apply/determinations/templates/determinations/includes/applicant_determination_block.html b/hypha/apply/determinations/templates/determinations/includes/applicant_determination_block.html index e0098e3324..4c70e57185 100644 --- a/hypha/apply/determinations/templates/determinations/includes/applicant_determination_block.html +++ b/hypha/apply/determinations/templates/determinations/includes/applicant_determination_block.html @@ -1,20 +1,17 @@ {% load i18n %} - - +
+ {% else %} +

{% trans "No reports submitted yet." %}

+ {% endif %} +
+ diff --git a/hypha/apply/projects/reports/templates/reports/modals/report_frequency_config.html b/hypha/apply/projects/reports/templates/reports/modals/report_frequency_config.html index c933eb4a64..a7139895f3 100644 --- a/hypha/apply/projects/reports/templates/reports/modals/report_frequency_config.html +++ b/hypha/apply/projects/reports/templates/reports/modals/report_frequency_config.html @@ -1,37 +1,40 @@ {% load i18n static %} -{% modal_title %}{% trans "Change reporting frequency" %}{% endmodal_title %} +{% trans "Change reporting frequency" %}
{{ report_data|json_script:"reportData" }} -
-

- {% if object.disable_reporting %} - {% trans "You'll need to configure reporting before you can use it. Please set the report date and frequency, then save the form." %} - {% elif object.does_not_repeat %} - {% if object.last_report %} - {% trans "No next report is due, One time reporting has already reported on " %} - {{ object.last_report.end_date }} +

+
+

+ {% if object.disable_reporting %} + {% trans "You'll need to configure reporting before you can use it. Please set the report date and frequency, then save the form." %} + {% elif object.does_not_repeat %} + {% if object.last_report %} + {% trans "No next report is due, One time reporting has already reported on " %} + {{ object.last_report.end_date }} + {% else %} + {% trans "Next report will be due on " %} + {{ object.schedule_start }} + {% trans "and it will be one-time reporting." %} + {% endif %} {% else %} - {% trans "Next report will be due on " %} - {{ object.schedule_start }} - {% trans "and it will be one-time reporting." %} + {% trans "Next report will be due in" %} + + {% trans "and the report period will be" %} + + {% trans "to" %} + + {% trans "and then every" %} + + + {% trans "after until the project end date" %}: + . {% endif %} - {% else %} - {% trans "Next report will be due in" %} - - {% trans "and the report period will be" %} - - {% trans "to" %} - - {% trans "and then every" %} - - - {% trans "after until the project end date" %}: - . - {% endif %} -

+

+
+
{% for field in form.visible_fields %} {% if field.name == 'occurrence' %} - -
+
+ {% trans 'Report every:' %} {% endif %} + {% if field.field %} {% include "forms/includes/field.html" %} {% else %} {{ field }} {% endif %} + {% if field.name == 'frequency' %} -
+ {% endif %} {% endfor %}
-
+
+ + - - +
diff --git a/hypha/apply/projects/reports/templates/reports/report_detail.html b/hypha/apply/projects/reports/templates/reports/report_detail.html index 7fc9efbb22..b33cf16e86 100644 --- a/hypha/apply/projects/reports/templates/reports/report_detail.html +++ b/hypha/apply/projects/reports/templates/reports/report_detail.html @@ -3,39 +3,67 @@ {% block title %}{% trans "Report" %} | {{ object.project.title }}{% endblock %} -{% block content %} - {% adminbar %} - {% slot back_link %} - - {% trans "View project page" %} - - {% endslot %} - {% slot header %}{{ object.project.title }} #{{ object.project.application_id }}{% endslot %} - {% slot sub_heading %}{% trans "Report" %}{% endslot %} - {% endadminbar %} +{% block hero %} + + + +{% endblock %} -
+{% block content %} +
+
+
+ + {% trans "Submitted " %} + + + {{ object.submitted|date:"SHORT_DATETIME_FORMAT" }} + + + {% trans "by" %} + + {{ object.author }} + + + + {% trans "Updated" %} + + + {{ object.current.submitted|date:"SHORT_DATETIME_FORMAT" }} + + + {% trans "by" %} + + {{ object.current.author }} + + +
-
-

- {% heroicon_outline 'exclamation-circle' stroke_width=2 size=18 class="inline me-1 stroke-dark-blue" aria_hidden=true %} +

{% if report.skipped %}

{% trans "Report Skipped" %}

{% else %} -

{% trans "Public Report" %}

-
- {% if object.current %} -
+

{% trans "Public Report" %}

+ + {% if object.current %} +
+
{{ object.current.output_answers }}
- {% endif %} -
+
+ {% endif %} {% for file in object.current.files.all %} {% if forloop.first %} @@ -51,36 +79,43 @@

{% trans "Attachments" %}

{% endfor %} {% endif %}
-
-
+ + diff --git a/hypha/apply/projects/reports/templates/reports/report_form.html b/hypha/apply/projects/reports/templates/reports/report_form.html index 11def7d783..cc7a59ca20 100644 --- a/hypha/apply/projects/reports/templates/reports/report_form.html +++ b/hypha/apply/projects/reports/templates/reports/report_form.html @@ -1,82 +1,91 @@ {% extends "base-apply.html" %} {% load i18n static heroicons %} -{% block extra_css %} - {{ block.super }} -{% endblock %} - {% block title %}{% trans "Edit Report" %} | {{ object.project.title }}{% endblock %} -{% block content %} - {% adminbar %} - {% slot back_link %} - - {% trans "View project page" %} - - {% endslot %} - {% slot header %}{{ object.project.title }}{% endslot %} - {% slot sub_heading %}{% trans "Submit a report" %}{% endslot %} - {% endadminbar %} - - {% if report_form %} +{% block hero %} + + + +{% endblock %} - {% include "forms/includes/form_errors.html" with form=form %} +{% block content %} +
-
-
+ {% if report_form %} + -

- {% heroicon_outline 'exclamation-circle' stroke_width=2 size=18 class="inline me-1 stroke-dark-blue" aria_hidden=true %} - - {% trans "This report is for the period" %} {{ object.start_date }} {% trans "to" %} {{ object.end_date }} - -

+
+ {% include "forms/includes/form_errors.html" with form=form %} + {% csrf_token %} - - {% csrf_token %} - {% for field in form %} - {% if field.field %} - {% if field.field.multi_input_field %} - {% include "forms/includes/multi_input_field.html" %} - {% else %} - {% include "forms/includes/field.html" %} - {% endif %} + {% for field in form %} + {% if field.field %} + {% if field.field.multi_input_field %} + {% include "forms/includes/multi_input_field.html" %} {% else %} -
+ {% include "forms/includes/field.html" %} + {% endif %} + {% else %} +
+
{{ field.block }}
- {% endif %} - {% endfor %} +
+ {% endif %} + {% endfor %} - {% for hidden_field in form.hidden_fields %} - {{ hidden_field }} - {% endfor %} - - - - - -
-
- {% else %} -
-
+ {% for hidden_field in form.hidden_fields %} + {{ hidden_field }} + {% endfor %} + +
+ + +
+ + {% else %} +

{% if request.user.is_apply_staff %} -

- {% trans "Project Report Form not configured. Please add a project report form in the" %} - {% trans "fund settings" %}. -

+ {% trans "Project report form not configured. Please add a project report form in the" %} + + {% trans "fund settings" %} + . {% else %} -

- {% trans "Project Report Form not configured yet. Please contact us at " %} - {{ ORG_EMAIL }}. -

+ {% trans "Project report rorm not configured yet. Please contact us at " %} + {{ ORG_EMAIL }}. {% endif %} -
-
- {% endif %} +

+ {% endif %} +
{% endblock %} {% block extra_js %} - + {% endblock %} diff --git a/hypha/apply/projects/reports/templates/reports/report_list.html b/hypha/apply/projects/reports/templates/reports/report_list.html index 3efb8e235d..748b247458 100644 --- a/hypha/apply/projects/reports/templates/reports/report_list.html +++ b/hypha/apply/projects/reports/templates/reports/report_list.html @@ -5,23 +5,25 @@ {% block title %}{% trans "Reports" %}{% endblock %} -{% block content %} +{% block hero %} + + + +{% endblock %} - {% adminbar %} - {% slot header %}{% trans "Submitted Reports" %} ({{ table.rows|length }}){% endslot %} - {% slot sub_heading %} - {% trans "View and filter all Submitted Reports" %} • - View all reports - {% endslot %} - {% endadminbar %} -
+{% block content %} +
{% if table %} {% include "funds/includes/table_filter_and_search.html" %} - {% render_table table %} +
+ {% render_table table %} +
{% else %}

{% trans "No Reports Available." %}

{% endif %}
- {% endblock content %} diff --git a/hypha/apply/projects/reports/templates/reports/reporting.html b/hypha/apply/projects/reports/templates/reports/reporting.html index ef635c46ac..4e11b35786 100644 --- a/hypha/apply/projects/reports/templates/reports/reporting.html +++ b/hypha/apply/projects/reports/templates/reports/reporting.html @@ -5,23 +5,24 @@ {% block title %}{% trans "Reporting" %}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "Reporting" %} ({{ table.rows|length }}){% endslot %} - {% slot sub_heading %} - {% trans "View, Search and filter reporting statuses" %} • - View submitted reports - {% endslot %} - {% endadminbar %} +{% block hero %} + + + +{% endblock %} -
+{% block content %} +
{% if table %} {% include "funds/includes/table_filter_and_search.html" %} - {% render_table table %} +
+ {% render_table table %} +
{% else %} -

{% trans "No Projects Currently Reporting." %}

+

{% trans "No Projects Currently Reporting." %}

{% endif %}
- {% endblock content %} diff --git a/hypha/apply/projects/tables.py b/hypha/apply/projects/tables.py index 5d833c56c7..ddac01e7bc 100644 --- a/hypha/apply/projects/tables.py +++ b/hypha/apply/projects/tables.py @@ -1,6 +1,9 @@ import json import django_tables2 as tables +from django.conf import settings +from django.urls import reverse +from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ @@ -8,6 +11,7 @@ from heroicons.templatetags.heroicons import heroicon_outline from hypha.apply.funds.tables import LabeledCheckboxColumn +from hypha.core.tables import RelativeTimeColumn from .forms.payment import get_invoice_possible_transition_for_user from .models import Invoice, PAFApprovals, Project @@ -23,14 +27,14 @@ def render_invoice_actions(table, record): class BaseInvoiceTable(tables.Table): invoice_number = tables.LinkColumn( "funds:projects:invoice-detail", - verbose_name=_("Invoice Number"), + verbose_name=_("Invoice #"), args=[tables.utils.A("project__submission__pk"), tables.utils.A("pk")], attrs={ "td": { "class": "js-title", # using title as class because of batch-actions.js }, "a": { - "class": "truncate inline-block w-[calc(100%-2rem)] after:content-[''] after:block", + "class": "link link-hover text-h4 font-semibold break-words line-clamp-2 max-w-md", }, }, ) @@ -39,22 +43,57 @@ class BaseInvoiceTable(tables.Table): ) requested_at = tables.DateColumn(verbose_name=_("Submitted")) invoice_date = tables.DateColumn(verbose_name=_("Invoice date")) + project = tables.Column( + verbose_name=_("Project Title"), attrs={"td": {"class": "max-w-md"}} + ) + class Meta: + row_attrs = { + "onclick": lambda record: f"window.location.href='{reverse('funds:projects:invoice-detail', args=[record.project.submission.pk, record.pk])}'", + "class": "table-row-link", + "role": "button", + "tabindex": "0", # Accessibility + } -class InvoiceDashboardTable(BaseInvoiceTable): - project = tables.Column(verbose_name=_("Project Name")) + def render_requested_at(self, record): + return format_html( + "{}", + record.requested_at.isoformat(), + record.requested_at.strftime(settings.SHORT_DATETIME_FORMAT), + ) - class Meta: + def render_status(self, record): + status = record.status + status_display = record.get_status_display() + + badge_class = { + "changes_requested_staff": "badge-warning", + "payment_failed": "badge-error", + "paid": "badge-success", + "declined": "badge-error", + } + + return format_html( + "{}", + badge_class.get(status, "badge-info"), + status, + status_display, + ) + + +class InvoiceDashboardTable(BaseInvoiceTable): + class Meta(BaseInvoiceTable.Meta): fields = [ - "requested_at", "invoice_number", + "requested_at", "status", "project", ] model = Invoice order_by = ["-requested_at"] template_name = "application_projects/tables/table.html" - attrs = {"class": "invoices-table"} + attrs = {"class": "table invoices-table invoivceDashboardTable"} + orderable = False def render_project(self, record): return get_project_title(record.project) @@ -65,27 +104,27 @@ class FinanceInvoiceTable(BaseInvoiceTable): selected = LabeledCheckboxColumn( accessor=A("pk"), attrs={ - "input": {"class": "js-batch-select"}, - "th__input": {"class": "js-batch-select-all"}, + "input": {"class": "js-batch-select checkbox"}, + "th__input": {"class": "js-batch-select-all checkbox"}, }, ) - class Meta: + class Meta(BaseInvoiceTable.Meta): fields = [ "selected", + "invoice_number", "invoice_date", - "requested_at", "vendor_name", - "invoice_number", - "invoice_amount", "status", + "requested_at", + "invoice_amount", ] model = Invoice orderable = True sequence = fields order_by = ["-requested_at", "invoice_date"] template_name = "application_projects/tables/table.html" - attrs = {"class": "invoices-table"} + attrs = {"class": "table border-x border-b mb-2 invoices-table"} row_attrs = { "data-record-id": lambda record: record.id, } @@ -102,18 +141,18 @@ class AdminInvoiceListTable(BaseInvoiceTable): "th": { "class": "w-8", }, - "input": {"class": "js-batch-select"}, - "th__input": {"class": "js-batch-select-all"}, + "input": {"class": "js-batch-select checkbox"}, + "th__input": {"class": "js-batch-select-all checkbox"}, }, ) - class Meta: + class Meta(BaseInvoiceTable.Meta): fields = [ "selected", "invoice_number", "invoice_date", - "requested_at", "status", + "requested_at", "project", ] model = Invoice @@ -121,7 +160,7 @@ class Meta: sequence = fields order_by = ["-requested_at"] template_name = "application_projects/tables/table.html" - attrs = {"class": "invoices-table"} + attrs = {"class": "table border-x border-b mb-2 invoices-table"} row_attrs = { "data-record-id": lambda record: record.id, } @@ -134,14 +173,19 @@ class BaseProjectsTable(tables.Table): title = tables.LinkColumn( "funds:submissions:project", args=[tables.utils.A("application_id")], + attrs={ + "a": { + "class": "link link-hover text-h4 font-semibold break-words line-clamp-2 max-w-md" + } + }, ) status = tables.Column( verbose_name=_("Status"), accessor="get_status_display", order_by=("status",) ) fund = tables.Column(verbose_name=_("Fund"), accessor="submission__page") reporting = tables.Column(verbose_name=_("Reporting"), accessor="pk") - last_payment_request = tables.DateColumn() - end_date = tables.DateColumn(verbose_name=_("End date"), accessor="proposed_end") + last_payment_request = RelativeTimeColumn() + end_date = RelativeTimeColumn(verbose_name=_("End date"), accessor="proposed_end") def order_reporting(self, qs, is_descending): direction = "-" if is_descending else "" @@ -182,7 +226,7 @@ class Meta: model = Project template_name = "application_projects/tables/table.html" orderable = False - attrs = {"class": "projects-table"} + attrs = {"class": "table projects-table"} class ProjectsAssigneeDashboardTable(BaseProjectsTable): @@ -198,7 +242,7 @@ class Meta: model = Project orderable = False exclude = ["status"] - attrs = {"class": "projects-table"} + attrs = {"class": "table projects-table"} class PAFForReviewDashboardTable(tables.Table): @@ -227,7 +271,7 @@ class Meta: template_name = ( "funds/tables/table.html" # todo: update it with Project table template ) - attrs = {"class": "paf-review-table"} + attrs = {"class": "table paf-review-table"} def order_date_requested(self, qs, is_descending): direction = "-" if is_descending else "" @@ -261,4 +305,4 @@ class Meta: orderable = True order_by = ("end_date",) template_name = "application_projects/tables/table.html" - attrs = {"class": "projects-table"} + attrs = {"class": "table projects-table"} diff --git a/hypha/apply/projects/templates/application_projects/includes/contracting_documents.html b/hypha/apply/projects/templates/application_projects/includes/contracting_documents.html index 8d3f98002d..4db2857495 100644 --- a/hypha/apply/projects/templates/application_projects/includes/contracting_documents.html +++ b/hypha/apply/projects/templates/application_projects/includes/contracting_documents.html @@ -1,162 +1,205 @@ {% load i18n contract_tools project_tags heroicons %} {% allow_collapsible_header object header_type='contracting_documents' as collapsible_header %} -
-
-
-

- {% trans "Contracting documents" %} -

+
+
- {% if collapsible_header %} - {% endif %}
- {% user_can_upload_contract object request.user as can_upload_contract %} - {% user_can_submit_contract object user contract as can_submit_contract %} - {% required_remaining_contracting_doc_categories remaining_contract_document_categories as required_remaining_contract_document_categories %} - {% if can_submit_contract %} - - {% trans "Submit contract documents" %} - - {% endif %} - {% user_can_approve_contract request.user object as can_approve_contract %} - {% if contract_to_approve and can_approve_contract %} - - {% trans "Approve contract documents" %} - + +
+ + diff --git a/hypha/apply/projects/templates/application_projects/includes/invoices.html b/hypha/apply/projects/templates/application_projects/includes/invoices.html index e86f7fe61b..840461c875 100644 --- a/hypha/apply/projects/templates/application_projects/includes/invoices.html +++ b/hypha/apply/projects/templates/application_projects/includes/invoices.html @@ -1,29 +1,31 @@ {% load i18n invoice_tools humanize heroicons %} {% load can from permission_tags %} -
-
-

{% trans "Invoices" %}

+
+
+

{% trans "Invoices" %}

+ {% can "add_invoice" object as can_add_invoice %} {% if can_add_invoice %} {% trans "Add Invoice" %} {% endif %} -
-
+ + +
{% if object.invoices.not_rejected %} - +
- - - - - + + + + + @@ -31,31 +33,30 @@

{% trans "Invoices" %}

{% trans "Date submitted" %}{% trans "Invoice date" %}{% trans "Invoice no." %}{% trans "Status" %}{% trans "Date submitted" %}{% trans "Invoice date" %}{% trans "Invoice no." %}{% trans "Status" %}
{% else %} -

{% trans "No active invoices yet." %}

+

{% trans "No active invoices yet." %}

{% endif %} {% if object.invoices.rejected %} -

+

{% trans "Show rejected" as showrejectedtext %} {% trans "Hide rejected" as hiderejectedtext %} - {{ showrejectedtext }} - +

- +
- - - - - + + + + + diff --git a/hypha/apply/projects/templates/application_projects/includes/project_documents.html b/hypha/apply/projects/templates/application_projects/includes/project_documents.html index e0515662ba..5ecaa2292f 100644 --- a/hypha/apply/projects/templates/application_projects/includes/project_documents.html +++ b/hypha/apply/projects/templates/application_projects/includes/project_documents.html @@ -1,166 +1,204 @@ {% load i18n approval_tools project_tags heroicons %} {% allow_collapsible_header object header_type='project_documents' as collapsible_header %} -
-
-
-

- {% trans "Project documents" %} -

+
+
+

+ {% trans "Project documents" %} +

-
- {% user_can_send_for_approval object user as can_send_to_approve %} - {% if can_send_to_approve %} - - {% if object.paf_approvals.exists %} - {% trans "Resubmit for approval" %} - {% else %} - {% trans "Submit for approval" %} - {% endif %} - - {% endif %} - {% user_can_update_paf_approvers object user request as can_update_paf_approvers %} - {% user_can_assign_approvers_to_project object user request as can_assign_paf_approvers %} - {% if can_update_paf_approvers %} - {% if user == project.lead %} - - {% trans "View/Update Approvers" %} - +
+ {% user_can_send_for_approval object user as can_send_to_approve %} + {% if can_send_to_approve %} + + {% if object.paf_approvals.exists %} + {% trans "Resubmit for approval" %} {% else %} - - {% trans "Change approver" %} - + {% trans "Submit for approval" %} {% endif %} - {% endif %} - {% if can_assign_paf_approvers %} - + {% endif %} + + {% user_can_update_paf_approvers object user request as can_update_paf_approvers %} + {% user_can_assign_approvers_to_project object user request as can_assign_paf_approvers %} + {% if can_update_paf_approvers %} + {% if user == project.lead %} + + {% trans "Update approvers" %} + + {% else %} + - {% trans "Assign approver" %} + {% trans "Change approver" %} {% endif %} - {% user_can_update_paf_status object user request=request as can_update_paf_status %} - {% if object.can_make_approval and can_update_paf_status %} - + {% trans "Assign approver" %} + + {% endif %} + + {% user_can_update_paf_status object user request=request as can_update_paf_status %} + {% if object.can_make_approval and can_update_paf_status %} + + {% trans "Update Status" %} + + {% endif %} + + {% if collapsible_header %} + + {% endif %} +
+
+ +
+
+

+ {% if object.user_has_updated_pf_details %} + {% heroicon_outline "check-circle" size=16 class="w-5 h-5 stroke-primary" stroke_width=2 aria_hidden=true %} + {% else %} + {% heroicon_outline "check-circle" size=16 class="w-5 h-5 stroke-gray-400" aria_hidden=true %} + {% endif %} + {% trans "Project form" %} +

+ +
+ {% user_can_edit_pfs object user as can_edit_pfs %} + {% if can_edit_pfs %} + - {% trans "Update Status" %} + {% if object.user_has_updated_pf_details %} + {% heroicon_micro "pencil-square" class="inline size-4" aria_hidden=true %} + {% trans "Edit" %} + {% else %} + {% trans "Fill in" %} + {% endif %} {% endif %} - {% if collapsible_header %} - + {% if object.user_has_updated_pf_details and not user.is_applicant %} + + {% heroicon_micro "eye" class="inline size-4" aria_hidden=true %} + {% trans "View" %} + {% endif %}
-
-
+ {% endif %} + - {% if supporting_documents_configured %} -
- {% heroicon_outline "check-circle" class="stroke-gray-400 me-1" aria_hidden=true %} -

{% trans "Supporting documents" %}

+ {% if supporting_documents_configured %} +
+

+ {% heroicon_outline "check-circle" size=16 class="w-5 h-5 stroke-gray-400" aria_hidden=true %} + {% trans "Supporting documents" %} +

+
-
-
-
-
+
+
+
+
- {% endif %} - -
- - -{% if can_update_paf_status %} - -{% endif %} +
+ {% endif %} +
+ diff --git a/hypha/apply/projects/templates/application_projects/includes/project_header.html b/hypha/apply/projects/templates/application_projects/includes/project_header.html index 7d1c433caf..ae6a8a20ad 100644 --- a/hypha/apply/projects/templates/application_projects/includes/project_header.html +++ b/hypha/apply/projects/templates/application_projects/includes/project_header.html @@ -1,21 +1,23 @@ -{% load dashboard_statusbar_tags %} +{% load dashboard_statusbar_tags i18n %}

- +

-
- {{ object.fund_name }} +
+ {{ object.fund_name }} {% if object.submission.round %} - + {% if request.user.is_apply_staff %} - {{ object.submission.round }} {% else %} {{ object.submission.round }} @@ -25,13 +27,15 @@ {% if not HIDE_STAFF_IDENTITY or request.user.is_org_faculty %} {% endif %} -
-{% project_status_bar object.status request.user css_class="w-full" %} + diff --git a/hypha/apply/projects/templates/application_projects/invoice_confirm_delete.html b/hypha/apply/projects/templates/application_projects/invoice_confirm_delete.html deleted file mode 100644 index b948fd71b3..0000000000 --- a/hypha/apply/projects/templates/application_projects/invoice_confirm_delete.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends "base-apply.html" %} -{% load i18n humanize invoice_tools %} - -{% block title %} {% trans "Invoice" %}: {{ object.project.title }}{% endblock %} -{% block content %} - {% display_invoice_status_for_user user object as invoice_status %} - - {% adminbar %} - {% slot back_link %} - - {% trans "View project page" %} - - {% endslot %} - {% slot header %}{% trans "Delete Invoice" %}{% endslot %} - {% slot sub_heading %}{% trans "For" %}: {{ object.project.title }}{% endslot %} - {% endadminbar %} - -
-
- -
-

{% trans "Status" %}: {{ invoice_status }}

-

{% trans "Vendor" %}: {{ object.project.user }}

-

{% trans "Invoice Number" %}: {{ object.pk }}

- -
-
-
{% csrf_token %} -

{% trans "Are you sure you want to delete this invoice for" %} {{ object.project.title }}?

- - - -
-
-
-{% endblock %} diff --git a/hypha/apply/projects/templates/application_projects/invoice_detail.html b/hypha/apply/projects/templates/application_projects/invoice_detail.html index 3462bcd756..96404239c6 100644 --- a/hypha/apply/projects/templates/application_projects/invoice_detail.html +++ b/hypha/apply/projects/templates/application_projects/invoice_detail.html @@ -1,63 +1,112 @@ {% extends "base-apply.html" %} -{% load i18n humanize invoice_tools heroicons %} +{% load i18n humanize invoice_tools heroicons apply_tags %} {% block title %}{% trans "Invoice" %}: {{ object.invoice_number }} - {{ object.project.title }}{% endblock %} + +{% block hero %} + + + +{% endblock %} + {% block content %} {% display_invoice_status_for_user user object as invoice_status %} {% can_show_paid_date invoice as show_paid_date %} +
+
- {% adminbar %} - {% slot back_link %} - - {% trans "View project page" %} - - {% endslot %} - {% slot header %}{% trans "Invoice" %}: {{ object.invoice_number }}{% endslot %} - {% slot sub_heading %}{% trans "For" %}: {{ object.project.title }}{% endslot %} - {% endadminbar %} + +
+
+

+ {% trans "Invoice number" %}: {{ object.invoice_number }} +

+

+ {% trans "Invoice date" %}: + {% if invoice.invoice_date %} + {{ invoice.invoice_date }} + {% else %} + {{ invoice.requested_at.date }} + {% endif %} +

+ {% if show_paid_date %} +

+ {% trans "Paid date" %}: {{ invoice.paid_date }} +

+ {% endif %} +

{% trans "Vendor" %}: + {{ object.project.user }}

+ {% if not HIDE_STAFF_IDENTITY or request.user.is_org_faculty %} +

+ {% trans "Lead" %}: {{ object.project.lead }} +

+ {% endif %} +

+ {% trans "Fund" %}: {{ object.project.submission.page }} +

+
+
-
-
-
-

{% trans "Invoice number" %}: {{ object.invoice_number }}

-

{% trans "Invoice date" %}: {% if invoice.invoice_date %}{{ invoice.invoice_date }}{% else %} {{ invoice.requested_at.date }} {% endif %}

- {% if show_paid_date %} -

{% trans "Paid date" %}: {{ invoice.paid_date }}

- {% endif %} -

{% trans "Vendor" %}: - {{ object.project.user }}

- {% if not HIDE_STAFF_IDENTITY or request.user.is_org_faculty %} -

{% trans "Lead" %}: {{ object.project.lead }}

- {% endif %} -

{% trans "Fund" %}: {{ object.project.submission.page }}

-
-
-
-
-
+ +
+
+
+
+
-
-
-
{% trans "Invoice" %}
-

{{object.filename}}

- + +
+
+

{% trans "Invoice" %}

+

+ +

+
+ +
- {% if object.supporting_documents.exists %} -
-
{% trans "Supporting Documents" %}
+
+ + {% if object.supporting_documents.exists %} +
+
+

{% trans "Supporting Documents" %}

{% for document in object.supporting_documents.all %} -

- +

+ {{document.filename}}

{% endfor %}
- {% endif %} -
-
-
+ + diff --git a/hypha/apply/projects/templates/application_projects/invoice_form.html b/hypha/apply/projects/templates/application_projects/invoice_form.html index 74fe22f8e6..167a74946b 100644 --- a/hypha/apply/projects/templates/application_projects/invoice_form.html +++ b/hypha/apply/projects/templates/application_projects/invoice_form.html @@ -1,49 +1,49 @@ {% extends "base-apply.html" %} {% load i18n static %} -{% block title %}{% if object %}{% trans "Edit" %}{% else %}{% trans "Add" %}{% endif %} {% trans "Invoice" %}: {% if object %}{{ object.project.title }}{% else %}{{ project.title }}{% endif %}{% endblock %} -{% block content %} +{% block title %} + {% if object %}{% trans "Edit" %}{% else %}{% trans "Add" %}{% endif %} + {% trans "invoice" %}: {% if object %}{{ object.project.title }}{% else %}{{ project.title }}{% endif %} +{% endblock %} - {% adminbar %} - {% slot back_link %} - - {% trans "View project page" %} - - {% endslot %} - {% slot header %} - {% if object %} - {% trans "Editing" %} - {% else %} - {% trans "Add" %} - {% endif %} - {% trans "Invoice" %} - {% endslot %} - {% slot sub_heading %} - {% if object %} - {{ object.project.title }} +{% block hero %} + + + +{% endblock %} + +{% block content %} +
+ {% include "forms/includes/form_errors.html" with form=form %} + {% csrf_token %} + {% for field in form %} + {% if field.field %} + {% include "forms/includes/field.html" %} {% else %} - {% trans "For" %}: {{ project.title }} + {{ field }} {% endif %} - {% endslot %} - {% endadminbar %} - - {% include "forms/includes/form_errors.html" with form=form %} + {% endfor %} -
-
- - {% csrf_token %} - {% for field in form %} - {% if field.field %} - {% include "forms/includes/field.html" %} - {% else %} - {{ field }} - {% endif %} - {% endfor %} - {% for button_name, button_type, button_value in buttons %} - - {% endfor %} - +
+ {% for button_name, button_type, button_value in buttons %} + + {% endfor %}
-
+ {% endblock %} diff --git a/hypha/apply/projects/templates/application_projects/invoice_list.html b/hypha/apply/projects/templates/application_projects/invoice_list.html index 98da39816d..278916b43f 100644 --- a/hypha/apply/projects/templates/application_projects/invoice_list.html +++ b/hypha/apply/projects/templates/application_projects/invoice_list.html @@ -5,14 +5,17 @@ {% block title %}{% trans "Invoices" %}{% endblock %} -{% block content %} - {% adminbar %} - {% slot header %}{% trans "All Invoices" %} ({{ table.rows|length }}){% endslot %} - {% slot sub_heading %}{% trans "View, search and filter all project invoices" %}{% endslot %} - {% endadminbar %} - -
+{% block hero %} + + + +{% endblock %} +{% block content %} +
{% if table %} {% trans "invoices" as search_placeholder %} {% include "funds/includes/table_filter_and_search.html" with search_term=search_term use_search=True invoice_batch_actions=True search_placeholder=search_placeholder %} diff --git a/hypha/apply/projects/templates/application_projects/modals/approve_contract.html b/hypha/apply/projects/templates/application_projects/modals/approve_contract.html index ac522b4c7b..2d0474c2df 100644 --- a/hypha/apply/projects/templates/application_projects/modals/approve_contract.html +++ b/hypha/apply/projects/templates/application_projects/modals/approve_contract.html @@ -1,5 +1,5 @@ {% load i18n %} -{% modal_title %}{% trans "Approve Contract" %}{% endmodal_title %} +{% trans "Approve contract" %}

diff --git a/hypha/apply/projects/templates/application_projects/modals/assign_pafapprovers.html b/hypha/apply/projects/templates/application_projects/modals/assign_pafapprovers.html index c891ecd4e6..7acd4b3703 100644 --- a/hypha/apply/projects/templates/application_projects/modals/assign_pafapprovers.html +++ b/hypha/apply/projects/templates/application_projects/modals/assign_pafapprovers.html @@ -1,12 +1,12 @@ {% load i18n %} {% if pafapprover_exists %} - {% modal_title %}{% trans "Assign Approver" %}{% endmodal_title %} + {% trans "Assign Approver" %} {% else %} - {% modal_title %}{% trans "Change Approver" %}{% endmodal_title %} + {% trans "Change Approver" %} {% endif %}

-

{% trans "Selected approver will be notified. On unselecting, every listed member here will be notified." %}

+

{% trans "Selected approver will be notified. If no one is selected, every listed member here will be notified." %}

{% include 'includes/dialog_form_base.html' with form=form value=value %}
diff --git a/hypha/apply/projects/templates/application_projects/modals/batch_invoice_status_update.html b/hypha/apply/projects/templates/application_projects/modals/batch_invoice_status_update.html index ff3276b2e1..8ba4055b0d 100644 --- a/hypha/apply/projects/templates/application_projects/modals/batch_invoice_status_update.html +++ b/hypha/apply/projects/templates/application_projects/modals/batch_invoice_status_update.html @@ -1,22 +1,36 @@ -{% load i18n %} -{% modal_title %}{% trans "Update Invoices Status" %}{% endmodal_title %} +{% load i18n heroicons %} +{% trans "Update Invoices Status" %}
-
-
- {{ invoices|length }} {% trans " invoices selected" %} - +
+ + + {% blocktrans count counter=invoices|length %} + {{ counter }} invoice selected + {% plural %} + {{ counter }} invoices selected + {% endblocktrans %} + + + - {% for invoice in invoices %} - - {{ invoice.invoice_number }} - - - - - - {% endfor %} -
+ + {% trans "Update status" as update %} {% include 'includes/dialog_form_base.html' with form=form value=update %}
diff --git a/hypha/apply/projects/templates/application_projects/modals/contracting_documents_upload.html b/hypha/apply/projects/templates/application_projects/modals/contracting_documents_upload.html index d3a07c0365..1ae7791207 100644 --- a/hypha/apply/projects/templates/application_projects/modals/contracting_documents_upload.html +++ b/hypha/apply/projects/templates/application_projects/modals/contracting_documents_upload.html @@ -1,5 +1,5 @@ {% load i18n %} -{% modal_title %}{% trans "Upload contracting documents" %}{% endmodal_title %} +{% trans "Upload contracting documents" %}
diff --git a/hypha/apply/projects/templates/application_projects/modals/invoice_confirm_delete.html b/hypha/apply/projects/templates/application_projects/modals/invoice_confirm_delete.html new file mode 100644 index 0000000000..fb4460fdf3 --- /dev/null +++ b/hypha/apply/projects/templates/application_projects/modals/invoice_confirm_delete.html @@ -0,0 +1,7 @@ +{% load i18n %} + + +

+ {% trans "Are you sure you want to delete this invoice? This action cannot be undone." %} +

+
diff --git a/hypha/apply/projects/templates/application_projects/modals/invoice_status_update.html b/hypha/apply/projects/templates/application_projects/modals/invoice_status_update.html index e67112f735..82f8bf5939 100644 --- a/hypha/apply/projects/templates/application_projects/modals/invoice_status_update.html +++ b/hypha/apply/projects/templates/application_projects/modals/invoice_status_update.html @@ -1,5 +1,5 @@ {% load i18n %} -{% modal_title %}{% trans "Update Invoice status" %}{% endmodal_title %} +{% trans "Update Invoice status" %}

{% trans "Current status" %}: {{ object.status_display }}

diff --git a/hypha/apply/projects/templates/application_projects/modals/lead_update.html b/hypha/apply/projects/templates/application_projects/modals/lead_update.html index ea7dfb2016..8d588066aa 100644 --- a/hypha/apply/projects/templates/application_projects/modals/lead_update.html +++ b/hypha/apply/projects/templates/application_projects/modals/lead_update.html @@ -1,5 +1,5 @@ {% load i18n %} -{% modal_title %}{% trans "Update Lead" %}{% endmodal_title %} +{% trans "Update Lead" %}
diff --git a/hypha/apply/projects/templates/application_projects/modals/pafstatus_update.html b/hypha/apply/projects/templates/application_projects/modals/pafstatus_update.html index 773ee1a1f4..a331e44ebe 100644 --- a/hypha/apply/projects/templates/application_projects/modals/pafstatus_update.html +++ b/hypha/apply/projects/templates/application_projects/modals/pafstatus_update.html @@ -1,5 +1,5 @@ {% load i18n project_tags %} -{% modal_title %}{% trans "Update Project Form Status" %}{% endmodal_title %} +{% trans "Project documents status" %}
{% include 'includes/dialog_form_base.html' with form=form value=value %} diff --git a/hypha/apply/projects/templates/application_projects/modals/project_dates_update.html b/hypha/apply/projects/templates/application_projects/modals/project_dates_update.html index 7a3248e18b..ed45e6684d 100644 --- a/hypha/apply/projects/templates/application_projects/modals/project_dates_update.html +++ b/hypha/apply/projects/templates/application_projects/modals/project_dates_update.html @@ -1,5 +1,5 @@ {% load i18n %} -{% modal_title %}{% trans "Update project dates" %}{% endmodal_title %} +{% trans "Update project dates" %}
{% include 'includes/dialog_form_base.html' with form=form value=value %} diff --git a/hypha/apply/projects/templates/application_projects/modals/project_status_update.html b/hypha/apply/projects/templates/application_projects/modals/project_status_update.html index c23efcc803..e6574c104b 100644 --- a/hypha/apply/projects/templates/application_projects/modals/project_status_update.html +++ b/hypha/apply/projects/templates/application_projects/modals/project_status_update.html @@ -1,5 +1,5 @@ {% load i18n %} -{% modal_title %}{% trans "Update Project Status" %}{% endmodal_title %} +{% trans "Update Project Status" %}
{% include 'includes/dialog_form_base.html' with form=form value=value %} diff --git a/hypha/apply/projects/templates/application_projects/modals/project_title_update.html b/hypha/apply/projects/templates/application_projects/modals/project_title_update.html index bc42e4dddd..a99fcbe4a6 100644 --- a/hypha/apply/projects/templates/application_projects/modals/project_title_update.html +++ b/hypha/apply/projects/templates/application_projects/modals/project_title_update.html @@ -1,5 +1,5 @@ {% load i18n %} -{% modal_title %}{% trans "Update title" %}{% endmodal_title %} +{% trans "Update title" %}
{% include 'includes/dialog_form_base.html' with form=form value=value %} diff --git a/hypha/apply/projects/templates/application_projects/modals/send_for_approval.html b/hypha/apply/projects/templates/application_projects/modals/send_for_approval.html index 6090208449..c114ea2e18 100644 --- a/hypha/apply/projects/templates/application_projects/modals/send_for_approval.html +++ b/hypha/apply/projects/templates/application_projects/modals/send_for_approval.html @@ -1,9 +1,10 @@ {% load i18n approval_tools project_tags heroicons %} -{% modal_title %}{% trans "Submit documents for review" %}{% endmodal_title %} -
+{% trans "Submit documents for review" %} + +
{% if remaining_document_categories %} -
+

{% trans "Looks like the following documents are missing" %}:

    @@ -16,7 +17,7 @@ {% endif %} {% if project_settings.paf_reviewers_roles.all %} -

    +

    {% trans "This will submit the project documents for review by the configured approvers." %} {% if project_settings.paf_approval_sequential %}{% trans "Approvers will review sequentially in order." %}{% else %}{% trans "Approvers can review in parallel at any time." %}{% endif %}

    @@ -25,13 +26,8 @@ {% trans "Note: All group members will be notified unless specific approvers are selected below." %}

    -
    -

    - {% trans "Select approvers " %} ({% trans "Optional" %}) -

    -

    -
    - +
    {% trans "Select approvers " %} ({% trans "Optional" %})
    + {% trans "Submit" as submit %} {% include 'includes/dialog_form_base.html' with form=form value=submit %} {% else %}

    diff --git a/hypha/apply/projects/templates/application_projects/modals/submit_contracting_documents.html b/hypha/apply/projects/templates/application_projects/modals/submit_contracting_documents.html index 31ee486f5e..e9d397e653 100644 --- a/hypha/apply/projects/templates/application_projects/modals/submit_contracting_documents.html +++ b/hypha/apply/projects/templates/application_projects/modals/submit_contracting_documents.html @@ -1,5 +1,5 @@ {% load i18n %} -{% modal_title %}{% trans "Submit contracting documents" %}{% endmodal_title %} +{% trans "Submit contracting documents" %}

    diff --git a/hypha/apply/projects/templates/application_projects/modals/supporting_documents_upload.html b/hypha/apply/projects/templates/application_projects/modals/supporting_documents_upload.html index 6f89205528..9e43d6710a 100644 --- a/hypha/apply/projects/templates/application_projects/modals/supporting_documents_upload.html +++ b/hypha/apply/projects/templates/application_projects/modals/supporting_documents_upload.html @@ -1,5 +1,5 @@ {% load i18n %} -{% modal_title %}{% trans "Upload Supporting Documents" %}{% endmodal_title %} +{% trans "Upload Supporting Documents" %}

    diff --git a/hypha/apply/projects/templates/application_projects/modals/update_pafapprovers.html b/hypha/apply/projects/templates/application_projects/modals/update_pafapprovers.html index 3b98cf1d62..c71f06508c 100644 --- a/hypha/apply/projects/templates/application_projects/modals/update_pafapprovers.html +++ b/hypha/apply/projects/templates/application_projects/modals/update_pafapprovers.html @@ -1,10 +1,10 @@ {% load i18n project_tags %} -{% modal_title %}{% trans "View/Update Approvers" %}{% endmodal_title %} +{% trans "View/Update Approvers" %}
    {% if project_settings.paf_reviewers_roles.all %} -

    {% trans "Are you sure you want to update the approvers?" %} {% if project_settings.paf_approval_sequential %} {% trans "The uppermost active approver will be notified via email." %} {% else %}{% trans "All approvers will be notified via email." %}{% endif %}

    -
    +

    {% trans "Are you sure you want to update the approvers?" %} {% if project_settings.paf_approval_sequential %} {% trans "The uppermost active approver will be notified via email." %} {% else %}{% trans "All approvers will be notified via email." %}{% endif %}

    + {% include 'includes/dialog_form_base.html' with form=form value=value %} {% else %}

    {% trans "No project form reviewer roles has been created yet, please create these in " %} diff --git a/hypha/apply/projects/templates/application_projects/modals/upload_contract.html b/hypha/apply/projects/templates/application_projects/modals/upload_contract.html index 1a653ba55c..16b2f231d4 100644 --- a/hypha/apply/projects/templates/application_projects/modals/upload_contract.html +++ b/hypha/apply/projects/templates/application_projects/modals/upload_contract.html @@ -1,14 +1,22 @@ {% load i18n project_tags %} {% if user.is_applicant %} - {% modal_title %}{% trans "Upload Countersigned Contract" %}{% endmodal_title %} + {% trans "Upload countersigned contract" %} {% else %} - {% modal_title %}{% trans "Upload Signed Contract" %}{% endmodal_title %} + {% trans "Upload signed contract" %} {% endif %} -

    +
    {% if not user.is_applicant %} -

    {% trans "The signed contract will be sent to Applicant once you submit. But if you select Signed and approved then it will directly be approved and project will move to Invoicing and Reporting." %}

    -
    +

    + {% trans "Upload a signed contract that will sent to applicant for countersigning." %} +

    +

    + {% blocktranslate trimmed %} + NOTE: Selecting "Signed and approved" indicates the uploaded contract is + already signed by both parties and the current project will move to the + invoicing & reporting stage. + {% endblocktranslate %} +

    {% endif %} {% include 'includes/dialog_form_base.html' with form=form value=value %}
    diff --git a/hypha/apply/projects/templates/application_projects/partials/contracting_category_documents.html b/hypha/apply/projects/templates/application_projects/partials/contracting_category_documents.html index e8fbc222df..fa8a400df7 100644 --- a/hypha/apply/projects/templates/application_projects/partials/contracting_category_documents.html +++ b/hypha/apply/projects/templates/application_projects/partials/contracting_category_documents.html @@ -1,98 +1,107 @@ {% load i18n apply_tags contract_tools project_tags heroicons %} -
  • -
    +
    +

    {% if not remaining_contract_document_categories %} - {% heroicon_outline "check-circle" class="stroke-light-blue me-1" aria_hidden=true %} + {% heroicon_outline "check-circle" size=16 class="w-5 h-5 stroke-primary" stroke_width=2 aria_hidden=true %} {% else %} - {% heroicon_outline "check-circle" class="stroke-gray-400 me-1" aria_hidden=true %} + {% heroicon_outline "check-circle" class="stroke-gray-400" aria_hidden=true %} {% endif %} -

    {% trans "Contracting documents" %}

    -

    - {% can_update_contracting_documents object user as can_update_documents %} + {% trans "Contracting documents" %} + + {% can_update_contracting_documents object user as can_update_documents %} {% if all_contract_document_categories %} -
    - -
    + {% endif %} +
  • + {% endfor %} +
{% endif %} - - +
{% required_remaining_contracting_doc_categories remaining_contract_document_categories as required_remaining_contract_document_categories %} {% user_can_submit_contract object user contract as can_submit_contract %} {% if can_submit_contract %} - {% trans "Submit contract documents" %} diff --git a/hypha/apply/projects/templates/application_projects/partials/invoice_detail_actions.html b/hypha/apply/projects/templates/application_projects/partials/invoice_detail_actions.html index 29c0b7645d..c750b13397 100644 --- a/hypha/apply/projects/templates/application_projects/partials/invoice_detail_actions.html +++ b/hypha/apply/projects/templates/application_projects/partials/invoice_detail_actions.html @@ -1,46 +1,63 @@ -{% load i18n invoice_tools %} +{% load i18n invoice_tools heroicons %} -
{% trans "Actions to take" %}
-{% can_edit object user as user_can_edit_request %} -{% if user.is_apply_staff or user.is_applicant %} - +

{% trans "Actions to take" %}

+ + + {% if user.is_org_faculty %} + {% can_change_status object user as user_can_change_status %} + {% if user_can_change_status %} + + {% else %} - "#" + {% endif %} - > - {% trans "Edit Invoice" %} -
-{% endif %} -{% can_delete object user as user_can_delete_request %} -{% if user_can_delete_request %} - - {% trans "Delete Invoice" %} - -{% endif %} + {% endif %} -{% if user.is_org_faculty %} - {% can_change_status object user as user_can_change_status %} - {% if user_can_change_status %} - - - {% else %} - + + {% can_edit object user as user_can_edit_request %} + {% if user.is_apply_staff or user.is_applicant %} + + {% heroicon_micro "pencil-square" aria_hidden=true class="opacity-80 size-4" %} + {% trans "Edit Invoice" %} + {% endif %} -{% endif %} + + + {% can_delete object user as user_can_delete_request %} + {% if user_can_delete_request %} + + {% heroicon_micro "trash" aria_hidden=true class="opacity-80 size-4" %} + {% trans "Delete" %} + + {% endif %} + +
diff --git a/hypha/apply/projects/templates/application_projects/partials/invoice_status.html b/hypha/apply/projects/templates/application_projects/partials/invoice_status.html index 9dab90e481..2566214e83 100644 --- a/hypha/apply/projects/templates/application_projects/partials/invoice_status.html +++ b/hypha/apply/projects/templates/application_projects/partials/invoice_status.html @@ -1,50 +1,74 @@ {% load i18n invoice_tools heroicons %} -
-

{% trans "Status" %}:

-
-
+
+

+ + {% trans "Status" %} +

+ {% extract_status latest_activity user as latest_activity_status %} {% get_comment_for_invoice_action object latest_activity as latest_activity_comment %} -

{{ latest_activity_status }} {% if user.is_applicant and latest_activity.user != user %} ({{ ORG_SHORT_NAME }}){% else %}({{ latest_activity.user }}){% endif %} - {{ latest_activity.timestamp }} +

+ {{ latest_activity_status }} + {% if user.is_applicant and latest_activity.user != user %} + ({{ ORG_SHORT_NAME }}) + {% else %} + ({{ latest_activity.user }}) + {% endif %} + + + {{ latest_activity.timestamp|date:'SHORT_DATETIME_FORMAT' }} + + {% if latest_activity_comment %} {% heroicon_outline "exclamation-circle" stroke_width=2 size=22 class="inline stroke-red-500" aria_hidden=true %} {% trans "View comment" %} {% endif %}

- {% for activity in activities %} - {% extract_status activity user as activity_status %} - {% get_comment_for_invoice_action object activity as activity_comment %} -

{{ activity_status }} {% if user.is_applicant and activity.user != user %} ({{ ORG_SHORT_NAME }}){% else %}({{ activity.user }}){% endif %} - {{ activity.timestamp }} - {% if activity_comment %} - {% heroicon_outline "exclamation-circle" stroke_width=2 size=22 class="inline stroke-red-500" aria_hidden=true %} - {% trans "View comment" %} - {% endif %} -

- {% endfor %} + + + {% if activities %} +
+ +
+ {% endif %}
-{% if activities %} - -{% endif %} diff --git a/hypha/apply/projects/templates/application_projects/partials/invoice_status_table.html b/hypha/apply/projects/templates/application_projects/partials/invoice_status_table.html index 1ba7c3cce6..ce515ed96c 100644 --- a/hypha/apply/projects/templates/application_projects/partials/invoice_status_table.html +++ b/hypha/apply/projects/templates/application_projects/partials/invoice_status_table.html @@ -3,40 +3,46 @@ {% for invoice in invoices %}
{% display_invoice_status_for_user user invoice as invoice_status %} - - - - - + + + + {% for column, cell in row.items %} {% endfor %} @@ -16,40 +13,15 @@ {% block pagination %} {% if table.page and table.paginator.num_pages > 0 %} -
-
+
+ - {% if table.paginator.num_pages > 1 %} -
    - {% if table.page.has_previous %} - - {% endif %} - {% if table.page.has_previous or table.page.has_next %} - {% total_num_of_pages table.rows|length table.paginator.per_page as total_pages %} -
  • -

    - {% trans "Page" %} {{ table.page.number }} / {{ total_pages }} -

    -
  • - {% endif %} - {% if table.page.has_next %} - - {% endif %} -
- {% endif %} +
{% endif %} {% endblock pagination %} diff --git a/hypha/apply/projects/templatetags/invoice_tools.py b/hypha/apply/projects/templatetags/invoice_tools.py index 9895aba196..fa23a38f02 100644 --- a/hypha/apply/projects/templatetags/invoice_tools.py +++ b/hypha/apply/projects/templatetags/invoice_tools.py @@ -7,8 +7,7 @@ from hypha.apply.activity.models import Activity from hypha.apply.activity.templatetags.activity_tags import display_for from hypha.apply.projects.constants import ( - INVOICE_STATUS_BG_COLORS, - INVOICE_STATUS_FG_COLORS, + INVOICE_STATUS_CLASSNAME_MAP, ) from hypha.apply.projects.models.payment import PAID from hypha.apply.projects.models.project import ( @@ -127,13 +126,8 @@ def get_comment_for_invoice_action(invoice, action): @register.filter -def invoice_status_bg_color(invoice_status): - return INVOICE_STATUS_BG_COLORS.get(invoice_status, "bg-gray-100") - - -@register.filter -def invoice_status_fg_color(invoice_status): - return INVOICE_STATUS_FG_COLORS.get(invoice_status, "text-gray-700") +def invoice_status_to_classname(invoice_status): + return INVOICE_STATUS_CLASSNAME_MAP.get(invoice_status, "badge") @register.simple_tag diff --git a/hypha/apply/projects/tests/test_forms.py b/hypha/apply/projects/tests/test_forms.py index f2efe2647a..c75309e414 100644 --- a/hypha/apply/projects/tests/test_forms.py +++ b/hypha/apply/projects/tests/test_forms.py @@ -195,19 +195,13 @@ def setUpTestData(cls): def test_paf_status_is_required(self): project = ProjectFactory(in_approval=True) - user = StaffFactory() - form = ChangePAFStatusForm( - data={"comment": "comment"}, instance=project, user=user - ) + form = ChangePAFStatusForm(data={"comment": "comment"}, instance=project) self.assertFalse(form.is_valid()) self.assertIn("paf_status", form.errors.keys()) def test_comment_is_not_required(self): project = ProjectFactory(in_approval=True) - user = StaffFactory() - form = ChangePAFStatusForm( - data={"paf_status": APPROVE}, instance=project, user=user - ) + form = ChangePAFStatusForm(data={"paf_status": APPROVE}, instance=project) self.assertTrue(form.is_valid()) self.assertEqual(form.errors, {}) diff --git a/hypha/apply/projects/urls.py b/hypha/apply/projects/urls.py index f8e07f262f..01c2b00e9d 100644 --- a/hypha/apply/projects/urls.py +++ b/hypha/apply/projects/urls.py @@ -37,8 +37,6 @@ UploadContractDocumentView, UploadContractView, UploadDocumentView, - get_invoices_status_counts, - get_project_status_counts, partial_contracting_documents, partial_get_invoice_detail_actions, partial_get_invoice_status, @@ -57,11 +55,7 @@ path("", RedirectView.as_view(pattern_name="apply:projects:all"), name="overview"), path("all/", ProjectListView.as_view(), name="all"), path("reports/", include("hypha.apply.projects.reports.urls"), name="reports"), - path("statuses/", get_project_status_counts, name="projects_status_counts"), path("invoices/", InvoiceListView.as_view(), name="invoices"), - path( - "invoices/statuses/", get_invoices_status_counts, name="invoices_status_counts" - ), path( "all/bulk_invoice_status_update/", BatchUpdateInvoiceStatusView.as_view(), diff --git a/hypha/apply/projects/utils.py b/hypha/apply/projects/utils.py index 1edb2256e5..a928a3793c 100644 --- a/hypha/apply/projects/utils.py +++ b/hypha/apply/projects/utils.py @@ -1,5 +1,3 @@ -import textwrap - from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ from django_file_form.uploaded_file import PlaceholderUploadedFile @@ -39,10 +37,9 @@ def get_project_title(project): - text = textwrap.shorten(project.title, width=40, placeholder="…") return format_html( PROJECT_TITLE_TEMPLATE, - text=text, + text=project.title, application_id=project.application_id, ) diff --git a/hypha/apply/projects/views/__init__.py b/hypha/apply/projects/views/__init__.py index 42317ac617..84396463fe 100644 --- a/hypha/apply/projects/views/__init__.py +++ b/hypha/apply/projects/views/__init__.py @@ -41,8 +41,6 @@ update_project_title, ) from .project_partials import ( - get_invoices_status_counts, - get_project_status_counts, partial_contracting_documents, partial_get_invoice_detail_actions, partial_get_invoice_status, @@ -62,8 +60,6 @@ "partial_get_invoice_status", "partial_get_invoice_detail_actions", "partial_contracting_documents", - "get_invoices_status_counts", - "get_project_status_counts", "BatchUpdateInvoiceStatusView", "ChangeInvoiceStatusView", "ChangeProjectstatusView", diff --git a/hypha/apply/projects/views/payment.py b/hypha/apply/projects/views/payment.py index 484136f638..489cbab52b 100644 --- a/hypha/apply/projects/views/payment.py +++ b/hypha/apply/projects/views/payment.py @@ -220,6 +220,7 @@ def post(self, *args, **kwargs): class DeleteInvoiceView(DeleteView): model = Invoice + template_name = "application_projects/modals/invoice_confirm_delete.html" def get_object(self): project = get_object_or_404(Project, submission__pk=self.kwargs["pk"]) @@ -280,7 +281,7 @@ def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) def buttons(self): - yield ("submit", "primary", _("Save")) + yield ("submit", "btn-primary", _("Save")) def get_context_data(self, **kwargs): return super().get_context_data( @@ -349,9 +350,9 @@ def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) def buttons(self): - yield ("submit", "primary", _("Save")) + yield ("submit", "btn-primary", _("Update")) if self.object.can_user_delete(self.request.user): - yield ("delete", "warning", _("Delete")) + yield ("delete", "btn-error", _("Delete")) def get_initial(self): initial = super().get_initial() diff --git a/hypha/apply/projects/views/project.py b/hypha/apply/projects/views/project.py index 38946b990b..8e89a9c5ca 100644 --- a/hypha/apply/projects/views/project.py +++ b/hypha/apply/projects/views/project.py @@ -2032,7 +2032,7 @@ class ProjectFormsEditView(BaseStreamForm, ProjectBySubmissionIdMixin, UpdateVie model = Project def buttons(self): - yield ("submit", "primary", _("Save")) + yield ("submit", "btn-primary", _("Save")) def dispatch(self, request, *args, **kwargs): self.object = self.get_object() diff --git a/hypha/apply/projects/views/project_partials.py b/hypha/apply/projects/views/project_partials.py index 45dcfcbda0..3f9c00433f 100644 --- a/hypha/apply/projects/views/project_partials.py +++ b/hypha/apply/projects/views/project_partials.py @@ -1,21 +1,15 @@ from typing import Optional -from urllib.parse import parse_qs, urlparse from django.contrib.auth.decorators import login_required -from django.db.models import Count, Q +from django.db.models import Q from django.http import HttpRequest from django.shortcuts import get_object_or_404, render -from django.urls import reverse_lazy -from django.utils.translation import gettext as _ from django.views.decorators.http import require_GET from hypha.apply.activity.models import Activity -from hypha.apply.funds.utils import get_statuses_as_params -from ..constants import statuses_and_table_statuses_mapping from ..models.payment import Invoice from ..models.project import ContractDocumentCategory, DocumentCategory, Project -from ..utils import get_project_status_choices @login_required @@ -83,84 +77,6 @@ def partial_contracting_documents(request, pk): ) -@login_required -@require_GET -def get_project_status_counts(request): - current_url = request.headers.get("Hx-Current-Url") - current_url_queries = parse_qs(urlparse(current_url).query) - project_status_url_query = current_url_queries.get("project_status") - project_status_counts = dict( - Project.objects.all() - .values("status") - .annotate( - count=Count("status"), - ) - .values_list( - "status", - "count", - ) - ) - status_counts = { - key: { - "name": display.replace(" and ", " & "), - "count": project_status_counts.get(key, 0), - "url": reverse_lazy("funds:projects:all") + "?project_status=" + key, - "is_active": True - if project_status_url_query and key in project_status_url_query - else False, - } - for key, display in get_project_status_choices() - } - - return render( - request, - "funds/includes/status-block.html", - { - "status_counts": status_counts, - "type": _("Projects"), - }, - ) - - -@login_required -@require_GET -def get_invoices_status_counts(request): - current_url = request.headers.get("Hx-Current-Url") - current_url_queries = parse_qs(urlparse(current_url).query) - invoice_status_url_query = current_url_queries.get("status") - invoices_status_counts = dict( - Invoice.objects.all() - .values("status") - .annotate( - count=Count("status"), - ) - .values_list( - "status", - "count", - ) - ) - status_counts = { - name: { - "name": name, - "count": sum(invoices_status_counts.get(status, 0) for status in statuses), - "url": reverse_lazy("funds:projects:invoices") - + get_statuses_as_params(statuses), - "is_active": True - if invoice_status_url_query and statuses == invoice_status_url_query - else False, - } - for name, statuses in statuses_and_table_statuses_mapping.items() - } - return render( - request, - "funds/includes/status-block.html", - { - "status_counts": status_counts, - "type": _("Invoices"), - }, - ) - - @login_required def partial_get_invoice_status_table( request: HttpRequest, pk: int, rejected: Optional[bool] = False diff --git a/hypha/apply/review/forms.py b/hypha/apply/review/forms.py index 22b3486afc..7353ce60c8 100644 --- a/hypha/apply/review/forms.py +++ b/hypha/apply/review/forms.py @@ -113,7 +113,7 @@ def calculate_score(self, data): class SubmitButtonWidget(forms.Widget): def render(self, name, value, attrs=None, renderer=None): disabled = "disabled" if attrs.get("disabled") else "" - return ''.format( + return ''.format( disabled=disabled, name=escape(name), value=escape(name.title()), diff --git a/hypha/apply/review/templates/review/includes/review_button.html b/hypha/apply/review/templates/review/includes/review_button.html index af730ac402..567a89670e 100644 --- a/hypha/apply/review/templates/review/includes/review_button.html +++ b/hypha/apply/review/templates/review/includes/review_button.html @@ -1,7 +1,9 @@ {% load i18n review_tags workflow_tags %} {% if request.user|has_review_perm:submission %} {% if request.user|has_draft:submission or request.user|can_review:submission %} - + {% if request.user|has_draft:submission %} {{ draft_text|default:"Update draft" }} {% elif request.user|can_review:submission %} diff --git a/hypha/apply/review/templates/review/includes/review_opinions_list.html b/hypha/apply/review/templates/review/includes/review_opinions_list.html index e186ced5b3..60dfbea606 100644 --- a/hypha/apply/review/templates/review/includes/review_opinions_list.html +++ b/hypha/apply/review/templates/review/includes/review_opinions_list.html @@ -1,13 +1,14 @@ {% load wagtailimages_tags %} {% if opinions %} -
{% trans "Date submitted" %}{% trans "Invoice date" %}{% trans "Invoice no." %}{% trans "Status" %}{% trans "Date submitted" %}{% trans "Invoice date" %}{% trans "Invoice no." %}{% trans "Status" %}
{% trans "Date submitted" %}: {{ invoice.requested_at.date }}{% trans "Invoice date" %}: {% if invoice.invoice_date %}{{ invoice.invoice_date }}{% else %} {{ invoice.requested_at.date }} {% endif %}{% trans "Invoice no." %}: {{ invoice.invoice_number }}{% trans "Status" %}: {{ invoice_status }} - - {% heroicon_micro "eye" aria_hidden=true class="me-1" %} + {{ invoice.requested_at.date }} + {% if invoice.invoice_date %} + {{ invoice.invoice_date }} + {% else %} + {{ invoice.requested_at.date }} + {% endif %} + {{ invoice.invoice_number }}{{ invoice_status }} + + {% heroicon_micro "eye" aria_hidden=true class="opacity-80" %} {% trans "View" %} {% if not rejected %} {% can_edit invoice user as user_can_edit_request %} {% if user_can_edit_request %} - {% heroicon_micro "pencil-square" aria_hidden=true class="me-1" %} - {% trans "Edit" %} + {% heroicon_micro "pencil-square" aria_hidden=true %} + {% trans "Edit" %} {% endif %} {% can_delete invoice user as user_can_delete_request %} - {% if user.is_applicant and user_can_delete_request %} + {% if not user.is_applicant and not user_can_delete_request %} - {% heroicon_micro "trash" aria_hidden=true class="me-1" %} - {% trans "Delete" %} + {% heroicon_micro "trash" aria_hidden=true %} + {% trans "Delete" %} {% endif %} {% can_change_status invoice user as can_change_invoice_status %} {% if can_change_invoice_status %} - {% endif %} diff --git a/hypha/apply/projects/templates/application_projects/partials/project_information.html b/hypha/apply/projects/templates/application_projects/partials/project_information.html index 71736a4060..620500d218 100644 --- a/hypha/apply/projects/templates/application_projects/partials/project_information.html +++ b/hypha/apply/projects/templates/application_projects/partials/project_information.html @@ -1,56 +1,62 @@ {% load i18n heroicons project_tags %} -
-
{% trans "Contractor" %}
-

{{ object.user |default:"-" }}

+ +
+
{% trans "Contractor" %}
+
{{ object.user |default:"-" }}
-
-
{% trans "E-mail" %}
- {% if object.user.email %} - {{ object.user.email }} - {% else %} - - - {% endif %} +
+
{% trans "E-mail" %}
+
+ {% if object.user.email %} + {{ object.user.email }} + {% else %} + - + {% endif %} +
-
- {% show_start_date object as show_start %} -
+
-

+ + + {% show_start_date object as show_start %} +

{% if show_start %} {{ object.proposed_start|date:"SHORT_DATE_FORMAT"|default:"-" }} {% else %} {% trans "Awaiting contract finalization..." %} {% endif %} -

+
-
-
+
-

{{ object.proposed_end|date:"SHORT_DATE_FORMAT"|default:"-" }}

+ +
{{ object.proposed_end|date:"SHORT_DATE_FORMAT"|default:"-" }}
diff --git a/hypha/apply/projects/templates/application_projects/partials/project_lead.html b/hypha/apply/projects/templates/application_projects/partials/project_lead.html index f5c351608d..8a4dfa707f 100644 --- a/hypha/apply/projects/templates/application_projects/partials/project_lead.html +++ b/hypha/apply/projects/templates/application_projects/partials/project_lead.html @@ -1,12 +1,13 @@ {% load i18n heroicons %} {% if request.user.is_apply_staff %} - - {% trans "Project lead" %}: {{ object.lead }} + {% trans "Project lead" %}: {{ object.lead }} {% heroicon_micro "pencil-square" class="inline ms-1" aria_hidden=true %} {% else %} diff --git a/hypha/apply/projects/templates/application_projects/partials/project_title.html b/hypha/apply/projects/templates/application_projects/partials/project_title.html index c1ce4dc8a6..5ccfa96757 100644 --- a/hypha/apply/projects/templates/application_projects/partials/project_title.html +++ b/hypha/apply/projects/templates/application_projects/partials/project_title.html @@ -1,15 +1,16 @@ {% load heroicons i18n %} {{ object.title }} -#{{ object.submission.application_id }} +#{{ object.submission.application_id }} {% if request.user.is_apply_staff %} - - {% heroicon_solid "pencil-square" class="inline mt-2 ms-1" aria_hidden=true %} + {% heroicon_mini "pencil-square" aria_hidden=true %} {% trans "edit title" %} {% endif %} diff --git a/hypha/apply/projects/templates/application_projects/partials/supporting_documents.html b/hypha/apply/projects/templates/application_projects/partials/supporting_documents.html index d7c05c5c10..8a0b0cf014 100644 --- a/hypha/apply/projects/templates/application_projects/partials/supporting_documents.html +++ b/hypha/apply/projects/templates/application_projects/partials/supporting_documents.html @@ -1,88 +1,89 @@ {% load i18n approval_tools apply_tags project_tags heroicons %} {% load can from permission_tags %} -
  • -
    +
    +

    {% if remaining_document_categories %} - {% heroicon_outline "check-circle" class="stroke-gray-400 me-1" aria_hidden=true %} + {% heroicon_outline "check-circle" size=16 class="w-5 h-5 stroke-gray-400" aria_hidden=true %} {% else %} - {% heroicon_outline "check-circle" class="stroke-light-blue me-1" aria_hidden=true %} + {% heroicon_outline "check-circle" size=16 class="w-5 h-5 stroke-primary" stroke_width=2 aria_hidden=true %} {% endif %} -

    {% trans "Supporting documents" %}

    -

    + {% trans "Supporting documents" %} + {% if all_document_categories %} + -
    + {% endfor %} + {% endif %} - -
  • +
    diff --git a/hypha/apply/projects/templates/application_projects/pdf_invoice_approved_page.html b/hypha/apply/projects/templates/application_projects/pdf_invoice_approved_page.html index 751c2b879f..6bbbcdd69d 100644 --- a/hypha/apply/projects/templates/application_projects/pdf_invoice_approved_page.html +++ b/hypha/apply/projects/templates/application_projects/pdf_invoice_approved_page.html @@ -1,4 +1,4 @@ -{% load invoice_tools i18n %} +{% load invoice_tools i18n tz %} @@ -7,7 +7,10 @@

    {% trans "Invoice Status" %}

      {% for activity in activities %} {% extract_status activity request.user as activity_status %} -
    • {{ activity_status }} ({{ activity.user.email }}) on {{ activity.timestamp }}
    • + {% get_current_timezone as TIME_ZONE %} +
    • + {% blocktrans with email=activity.user.email time=activity.timestamp|localtime %} {{ activity_status }} ({{ email }}) on {{ time }} {{ TIME_ZONE }}{% endblocktrans %} +
    • {% endfor %}
    diff --git a/hypha/apply/projects/templates/application_projects/project_admin_detail.html b/hypha/apply/projects/templates/application_projects/project_admin_detail.html index c9a64d05ec..24093ea9c5 100644 --- a/hypha/apply/projects/templates/application_projects/project_admin_detail.html +++ b/hypha/apply/projects/templates/application_projects/project_admin_detail.html @@ -2,36 +2,33 @@ {% load i18n approval_tools contract_tools project_tags static %} - {% block admin_assignments %} {% user_can_update_project_status object user as can_update_status %} {% if can_update_status %} -
    {% endif %} {% endblock %} diff --git a/hypha/apply/projects/templates/application_projects/project_approval_detail.html b/hypha/apply/projects/templates/application_projects/project_approval_detail.html index 9379d661b0..03bdb87f5d 100644 --- a/hypha/apply/projects/templates/application_projects/project_approval_detail.html +++ b/hypha/apply/projects/templates/application_projects/project_approval_detail.html @@ -1,145 +1,189 @@ {% extends "base-apply.html" %} -{% load i18n static approval_tools project_tags apply_tags %} +{% load i18n heroicons static approval_tools project_tags apply_tags %} {% block title %}{{ object.title }}{% endblock %} +{% block hero %} + + + +{% endblock %} + {% block content %} - {% adminbar %} - {% slot back_link %} - - {% trans "Back to Project" %} - - {% endslot %} - - {% slot header %} - {{ object.title }} - {% endslot %} - {% slot sub_heading %} -
    - {{ object.submission.page }} - {{ object.submission.round }} - {% trans "Lead" %}: {{ object.lead }} -
    - {% endslot %} - {% endadminbar %} - -
    -
    -
    -

    {% trans "Project Information" %}

    -
    - {% if object.output_answers %} -
    - {{ object.output_answers }} +
    +
    +
    + +
    +

    {% trans "Project Information" %}

    + +
    +
    + {% if object.output_answers %} +
    + {{ object.output_answers }} +
    + {% endif %} + + {% has_project_sow_form object as project_sow %} + {% if project_sow and object.sow.output_answers %} +
    + {{ object.sow.output_answers }} +
    + {% endif %}
    - {% endif %} +
    +
    - {% has_project_sow_form object as project_sow %} - {% if project_sow and object.sow.output_answers %} -
    - {{ object.sow.output_answers }} +
    +

    {% trans "Approvals" %}

    +
    +
    + {% for approval in project.paf_approvals.all %} + {% if approval.approved %} +

    {{ approval.paf_reviewer_role.label }} - {{ approval.user }} ({{ approval.approved_at|date:"DATE_FORMAT" }})

    + {% else %} +

    + {{ approval.paf_reviewer_role.label }}: + {% trans "Pending" %} +

    + {% endif %} + {% endfor %}
    - {% endif %} -
    - -

    {% trans "Approvals" %}

    -
    - {% for approval in project.paf_approvals.all %} - {% if approval.approved %} -

    {{ approval.paf_reviewer_role.label }} - {{ approval.user }} ({{ approval.approved_at|date:"DATE_FORMAT" }})

    - {% else %} -

    {{ approval.paf_reviewer_role.label }} {% trans " - Pending" %}

    - {% endif %} - {% endfor %} -
    - -

    {% trans "Reviews" %}

    -
    -

    {% trans "Submission lead" %}

    -

    {{ project.submission.lead }}

    - -

    {% trans "Staff reviewers" %}

    - {% for review in project.submission.reviews.by_staff %} -

    - {{ review.author }} - {% if review.author.role %} - {% trans "as" %} {{ review.author.role }} - {% endif %} - - {{ review.created_at|date:"DATE_FORMAT" }} -

    - {% empty %} -

    {% trans "No reviews" %}

    - {% endfor %} -

    {% trans "Advisory council" %}

    - {% for review in project.submission.reviews.by_reviewers %} -

    - {{ review.author }} - {{ review.created_at|date:"DATE_FORMAT" }} -

    - {% empty %} -

    {% trans "No reviews" %}

    - {% endfor %} -
    - -

    {% trans "Supporting Documents" %}

    -
    -

    {% trans "Application" %}

    - {% for packet_file in object.packet_files.all %} -

    {{ packet_file.title }}

    - {% endfor %} -
    +
    + + +
    +

    {% trans "Reviews" %}

    +
    +
    + +

    {% trans "Submission lead" %}:

    +

    {{ project.submission.lead }}

    + +

    {% trans "Staff reviewers" %}

    + + {% for review in project.submission.reviews.by_staff %} +

    + {{ review.author }} + {% if review.author.role %} + {% trans "as" %} {{ review.author.role }} + {% endif %} + - + + {{ review.created_at|date:'SHORT_DATETIME_FORMAT' }} + +

    + {% empty %} +

    {% trans "No reviews" %}

    + {% endfor %} + +

    {% trans "Advisory council" %}

    + {% for review in project.submission.reviews.by_reviewers %} +

    + {{ review.author }} - + {{ review.created_at|date:'SHORT_DATETIME_FORMAT' }} + +

    + {% empty %} +

    {% trans "No reviews" %}

    + {% endfor %} +
    +
    +
    + +
    +

    {% trans "Supporting Documents" %}

    + + +
    - {% user_can_update_paf_status object user request=request as can_update_paf_status %} + {% user_can_take_actions object user as can_take_actions %} {% if can_take_actions %} - {% endif %} diff --git a/hypha/apply/projects/templates/application_projects/project_approval_form.html b/hypha/apply/projects/templates/application_projects/project_approval_form.html index 4bdbb79795..3b3c3d5e74 100644 --- a/hypha/apply/projects/templates/application_projects/project_approval_form.html +++ b/hypha/apply/projects/templates/application_projects/project_approval_form.html @@ -1,24 +1,32 @@ {% extends "base-apply.html" %} -{% load i18n static %} +{% load i18n static heroicons apply_tags %} {% block title %}{% trans "Editing" %}: {{object.title }}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot back_link %} - - {% trans "View project page" %} - - {% endslot %} - {% slot header %}{% trans "Editing" %}: {{ object.title }}{% endslot %} - {% endadminbar %} - {% if approval_form_exists %} - {% include "forms/includes/form_errors.html" with form=pf_form %} +{% block hero %} + + + +{% endblock %} -
    -
    -
    +{% block content %} +
    +
    + {% if approval_form_exists %} +

    {% trans "Project form" %}

    + {% csrf_token %} + + {% include "forms/includes/form_errors.html" with form=pf_form %} + {% for field in pf_form %} {% if field.field %} {% if field.field.multi_input_field %} @@ -28,7 +36,9 @@ {% endif %} {% else %}
    - {{ field.block }} +
    + {{ field.block }} +
    {% endif %} {% endfor %} @@ -38,36 +48,52 @@ {{ hidden_field }} {% endfor %} - {% trans "Save draft" as save_draft %} - {% for button_name, button_type, button_value in buttons %} - - {% endfor %} - -
    - -
    - - {% else %} -
    -
    -

    + + {% else %} +

    {% trans "Project Form not configured. Please add an project form in the" %} {% trans "fund settings" %}.

    -
    -
    + {% endif %} +
    - {% endif %} + {% if approval_form_exists and submissions_attachments %} + + {% endif %} +
    {% endblock %} {% block extra_css %} @@ -76,7 +102,7 @@
    {% trans "Proposal attachments" %}
    {% block extra_js %} {{ pf_form.media.js }} - + {% if not show_all_group_fields %} {% endif %} diff --git a/hypha/apply/projects/templates/application_projects/project_detail.html b/hypha/apply/projects/templates/application_projects/project_detail.html index 0171c43920..ea42ad7c03 100644 --- a/hypha/apply/projects/templates/application_projects/project_detail.html +++ b/hypha/apply/projects/templates/application_projects/project_detail.html @@ -5,82 +5,75 @@ {% block title %}{{ object.title }}{% endblock %} -{% block body_class %}{% endblock %} - -{% block content %} -
    -
    - - {% include "application_projects/includes/project_header.html" %} - - +{% block hero %} + + {% include "application_projects/includes/project_header.html" %} + + -
    - - {% show_closing_banner object as show_banner %} - {% if show_banner %} -
    - {% display_project_status object request.user as project_status %} - {% blocktrans with status=project_status %} This project is in {{ status }} state. {% endblocktrans %} -
    - {% endif %} + +{% endblock %} -
    - {% block notifications %}{% endblock %} +{% block content %} +
    + + {% block notifications %} + {% show_closing_banner object as show_banner %} + {% if show_banner %} +
    + {% display_project_status object request.user as project_status %} + {% blocktrans with status=project_status %} This project is in {{ status }} state. {% endblocktrans %} +
    + {% endif %} + {% endblock %}
    -
    -

    {% trans "Project Information" %}

    -
    - - - - -
    +
    +
    +

    + {% trans "Project Information" %} +

    + +
    + {% include "application_projects/partials/project_information.html" %} +
    +
    {% project_can_have_invoices object as can_have_invoices %} {% user_can_view_invoices object user as can_view_invoices %} {% if can_have_invoices and can_view_invoices %} -
    - {% include "application_projects/includes/invoices.html" %} -
    + {% include "application_projects/includes/invoices.html" %} {% endif %} {% project_show_reports_section object as show_reports_section %} {% user_can_view_reports object user as can_view_reports %} {% if show_reports_section and can_view_reports %} -
    - {% include "reports/includes/reports.html" %} -
    + {% include "reports/includes/reports.html" %} {% endif %} {% project_can_have_contracting_section object as can_have_contracting_section %} @@ -99,76 +92,85 @@

    {% trans "Project Information" %}

    {% endblock sidebar %}
    @@ -192,6 +196,5 @@
    {% trans "Project form approvals" %}
    {% block extra_js %} - {% endblock %} diff --git a/hypha/apply/projects/templates/application_projects/project_form.html b/hypha/apply/projects/templates/application_projects/project_form.html index e3cedc53b3..6def158f0a 100644 --- a/hypha/apply/projects/templates/application_projects/project_form.html +++ b/hypha/apply/projects/templates/application_projects/project_form.html @@ -4,35 +4,35 @@ {% block title %}{% trans "Editing" %}: {{ object.title }}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "Editing" %}: {{ object.title}}{% endslot %} - {% endadminbar %} - - {% include "forms/includes/form_errors.html" with form=form %} - -
    -
    -
    - {% csrf_token %} - {% for field in form %} - {% if field.field %} - {% include "forms/includes/field.html" %} - {% else %} - {{ field }} - {% endif %} - {% endfor %} - - - {% trans "Cancel" %} - +{% block hero %} + + + +{% endblock %} - -
    -
    + + {% trans "Cancel" %} + +
    +
    {% endblock %} diff --git a/hypha/apply/projects/templates/application_projects/project_list.html b/hypha/apply/projects/templates/application_projects/project_list.html index e2273617f4..49aee5669e 100644 --- a/hypha/apply/projects/templates/application_projects/project_list.html +++ b/hypha/apply/projects/templates/application_projects/project_list.html @@ -5,20 +5,25 @@ {% block title %}{% trans "Projects" %}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "All Projects" %} ({{ table.rows|length }}){% endslot %} - {% slot sub_heading %}{% trans "View, Search and filter all projects" %}{% endslot %} - {% endadminbar %} +{% block hero %} + + + +{% endblock %} -
    +{% block content %} +
    {% if table %} {% include "funds/includes/table_filter_and_search.html" with search_term=search_term search_placeholder="projects" use_search=True %} - {% render_table table %} + +
    + {% render_table table %} +
    {% else %} -

    {% trans "No Projects Available." %}

    +

    {% trans "No Projects Available." %}

    {% endif %}
    - {% endblock content %} diff --git a/hypha/apply/projects/templates/application_projects/project_sow_detail.html b/hypha/apply/projects/templates/application_projects/project_sow_detail.html index 00b79d4473..0ef15d60f1 100644 --- a/hypha/apply/projects/templates/application_projects/project_sow_detail.html +++ b/hypha/apply/projects/templates/application_projects/project_sow_detail.html @@ -1,64 +1,62 @@ {% extends "application_projects/project_approval_detail.html" %} -{% load i18n static approval_tools project_tags apply_tags %} +{% load i18n static approval_tools project_tags apply_tags heroicons %} -{% block content %} - {% adminbar %} - {% slot back_link %} - - {% trans "Back to Project" %} - - {% endslot %} +{% block hero %} + + + +{% endblock %} - {% slot header %} - {{ object.title }} - {% endslot %} - {% slot sub_heading %} -
    - {{ object.submission.page }} - {{ object.submission.round }} - {% trans "Lead" %}: {{ object.lead }} -
    - {% endslot %} - {% endadminbar %} +{% block content %} +
    +
    +
    +

    {% trans "Scope of Work" %}

    -
    -
    -
    -

    {% trans "Scope of Work" %}

    -
    +
    {% if object.sow.output_answers %} -
    +
    {{ object.sow.output_answers }}
    {% endif %}
    + {% user_can_take_actions object user as can_take_actions %} {% if can_take_actions %} -
    - {% if column.name != "selected" %} - {{ column.header }}: - {% endif %} {% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}
    +{% block content %} +
    + {% comment %}
    {% endcomment %} +
    {% for answers in review_data.values %} diff --git a/hypha/apply/review/templates/review/reviewopinion_confirm_delete.html b/hypha/apply/review/templates/review/reviewopinion_confirm_delete.html index 6f414f8434..ff44882be4 100644 --- a/hypha/apply/review/templates/review/reviewopinion_confirm_delete.html +++ b/hypha/apply/review/templates/review/reviewopinion_confirm_delete.html @@ -1,21 +1,10 @@ -{% extends "base-apply.html" %} {% load i18n %} -{% block title %}{% trans "Deleting" %}: {{ object }}{% endblock %} - -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "Deleting" %}: {{ object }}{% endslot %} - {% endadminbar %} - -
    -
    -
    - {% csrf_token %} -

    {% trans "Are you sure you want to delete" %} "{{ object }}"?

    - - -
    -
    -{% endblock %} + +

    + {% blocktranslate trimmed with user=object.author %} + Are you sure you want to delete this review opinion by {{ user }}? + This action cannot be undone. + {% endblocktranslate %} +

    +
    diff --git a/hypha/apply/review/tests/test_views.py b/hypha/apply/review/tests/test_views.py index 3afeaf32b6..99fb15c246 100644 --- a/hypha/apply/review/tests/test_views.py +++ b/hypha/apply/review/tests/test_views.py @@ -252,7 +252,7 @@ def test_review_detail_recommendation(self): ) response = self.get_page(review) self.assertContains(response, submission.title) - self.assertContains(response, "

    Yes

    ") + self.assertContains(response, "Yes") def test_review_detail_opinion(self): staff = StaffFactory() diff --git a/hypha/apply/stream_forms/templates/stream_forms/heading_field.html b/hypha/apply/stream_forms/templates/stream_forms/heading_field.html index 1e97bc724e..5f2cd37389 100644 --- a/hypha/apply/stream_forms/templates/stream_forms/heading_field.html +++ b/hypha/apply/stream_forms/templates/stream_forms/heading_field.html @@ -1,10 +1,11 @@ {% load heroicons %} -
    - <{{ self.size }} tabindex="-1" class="p-2 mb-2 text-white bg-light-blue"> + +
    + <{{ self.size }} tabindex="-1" class="p-2 section-head" id="{{ value.heading_text|slugify }}""> {{ value.heading_text }} diff --git a/hypha/apply/stream_forms/templates/stream_forms/render_field.html b/hypha/apply/stream_forms/templates/stream_forms/render_field.html index 57b5571a7a..31ac559517 100644 --- a/hypha/apply/stream_forms/templates/stream_forms/render_field.html +++ b/hypha/apply/stream_forms/templates/stream_forms/render_field.html @@ -1,9 +1,11 @@ {% if include_question %}
    -

    {{ value.field_label }}

    +

    + {{ value.field_label }} +

    {% endif %} -
    +
    {% block data_display %}

    {{ data }}

    {% endblock %}
    diff --git a/hypha/apply/stream_forms/templates/stream_forms/render_file_field.html b/hypha/apply/stream_forms/templates/stream_forms/render_file_field.html index f82f80d25c..6fd95d2db2 100644 --- a/hypha/apply/stream_forms/templates/stream_forms/render_file_field.html +++ b/hypha/apply/stream_forms/templates/stream_forms/render_file_field.html @@ -1,7 +1,7 @@ {% extends "stream_forms/render_field.html" %} {% block data_display %} {% if data.name %} -
    +
    {% include "stream_forms/includes/file_field.html" with file=data %}
    {% else %} diff --git a/hypha/apply/stream_forms/templates/stream_forms/render_multi_file_field.html b/hypha/apply/stream_forms/templates/stream_forms/render_multi_file_field.html index f29dd76e06..316897b8e4 100644 --- a/hypha/apply/stream_forms/templates/stream_forms/render_multi_file_field.html +++ b/hypha/apply/stream_forms/templates/stream_forms/render_multi_file_field.html @@ -1,6 +1,6 @@ {% extends "stream_forms/render_field.html" %} {% block data_display %} -
    +
    {% for file in data %} {% if file.name %} {% include "stream_forms/includes/file_field.html" with file=file %} diff --git a/hypha/apply/templates/forms/includes/field.html b/hypha/apply/templates/forms/includes/field.html index 13942d0802..7005e868d3 100644 --- a/hypha/apply/templates/forms/includes/field.html +++ b/hypha/apply/templates/forms/includes/field.html @@ -1,115 +1,118 @@ {% load i18n util_tags heroicons %} {% with widget_type=field|widget_type field_type=field|field_type %} -
    1 %} - data-hidden="{% if not show_all_group_fields and not field.field.visible %}true{% else %}false{% endif %}" - data-required="{{ field.field.required_when_visible }}" - {% endif %} - {% if field.field.word_limit %} - data-word-limit="{{ field.field.word_limit }}" - {% endif %} - {% if widget_type == 'text_input' and field.field.max_length %} - data-maxlength="{{ field.field.max_length }}" - x-data="{ - titleblock: '', - maxlength: $el.dataset.maxlength, - get curlength() { return this.titleblock.length } - }" - {% endif %} +
    1 %} + data-hidden="{% if not show_all_group_fields and not field.field.visible %}true{% else %}false{% endif %}" + data-required="{{ field.field.required_when_visible }}" + {% endif %} + {% if field.field.word_limit %} + data-word-limit="{{ field.field.word_limit }}" + {% endif %} + {# fmt:off #} + {% if widget_type == 'text_input' and field.field.max_length %} + x-data=" + { + curlength: 0, + maxlength: 0, + get visible() { + return this.curlength >= this.maxlength * 0.8; + }, + init() { + const input = this.$el.querySelector('input'); + this.maxlength = input.maxLength; + this.curlength = input.value.length; + input.addEventListener('input', (e) => { + this.curlength = e.target.value.length; + }); + } + }" + {% endif %} + {# fmt:on #} > - {% if widget_type == 'clearable_file_input' or widget_type == 'multi_file_input' or widget_type == 'single_file_field_widget' or widget_type == 'multi_file_field_widget'%} - - {{ field.label }} - {% if field.field.required %} - * - {% endif %} - + {% if widget_type == 'clearable_file_input' or widget_type == 'multi_file_input' or widget_type == 'single_file_field_widget' or widget_type == 'multi_file_field_widget' %} +
    + {{ field.label }} {% if field.field.required %}*{% endif %} +
    {% elif widget_type == 'checkbox_select_multiple' or widget_type == 'radio_select' %} -
    - - {{ field.label }} - {% if field.field.required %} - * + + {{ field.label }} {% if field.field.required %}*{% endif %} + + {% elif widget_type == 'checkbox_input' %} +
    + {{ field }} +
    + + {% if field.help_text %} +
    {{ field.help_text }}
    {% endif %} - +
    +
    {% else %} - {% if not field.is_hidden and widget_type != 'checkbox_input' %} + {% if field.label and not field.is_hidden and widget_type != 'checkbox_input' %} {% endif %} {% endif %} - - {% if field.help_text %} -
    {{ field.help_text }}
    + {% if field.help_text and widget_type != 'checkbox_input' %} +
    + {{ field.help_text }} +
    {% endif %} - {% if not field.is_hidden %} -
    - {% if widget_type == 'date_input' or widget_type == 'date_time_input' %} -
    - {% endif %} + {% if widget_type == 'date_input' or widget_type == 'date_time_input' %} +
    + {% endif %} + {% if widget_type != "checkbox_input" %} {{ field }} + {% endif %} - {% if field.errors %} -

    - {{ field.errors.as_text|linebreaksbr }} -

    - {% endif %} - {% if widget_type == 'clearable_file_input' or widget_type == 'multi_file_input' %} - - {% endif %} - {% if widget_type == 'checkbox_input' %} - - {% endif %} - {% if widget_type == 'date_input' or widget_type == 'date_time_input' %} -
    - {% endif %} + {% if field.errors %} +

    + {{ field.errors.as_text|linebreaksbr }} +

    + {% endif %} - {% if widget_type == 'text_input' and field.field.max_length %} -
    /
    - {% endif %} -
    + {% if widget_type == 'clearable_file_input' or widget_type == 'multi_file_input' %} + + {% endif %} + + {% if widget_type == 'date_input' or widget_type == 'date_time_input' %} +
    + {% endif %} {% else %} {{ field }} {% endif %} - {% if widget_type == 'checkbox_select_multiple' or widget_type == 'radio_select' %} -
    + {% if widget_type == 'text_input' and field.field.max_length %} +
    + / +
    {% endif %} -
    + {% endwith %} diff --git a/hypha/apply/templates/forms/includes/form_errors.html b/hypha/apply/templates/forms/includes/form_errors.html index f3f17c5eed..6ca13e8a47 100644 --- a/hypha/apply/templates/forms/includes/form_errors.html +++ b/hypha/apply/templates/forms/includes/form_errors.html @@ -1,9 +1,9 @@ {% load i18n heroicons %} {% if form.errors or form.non_field_errors %} -
    - {% heroicon_solid "exclamation-triangle" class="inline me-1 fill-red-500" aria_hidden=true %} -
    {% trans "There were some errors with your form. Please amend the fields highlighted below." %}
    + diff --git a/hypha/apply/todo/templates/todo/todolist_item.html b/hypha/apply/todo/templates/todo/todolist_item.html index d397337314..c4697d51f1 100644 --- a/hypha/apply/todo/templates/todo/todolist_item.html +++ b/hypha/apply/todo/templates/todo/todolist_item.html @@ -1,24 +1,20 @@ {% load i18n markdown_tags nh3_tags heroicons %}
    - {% heroicon_outline task.icon class="w-4 h-4 group-hover:stroke-2 stroke-fg-muted" aria_hidden=true %} + {% heroicon_outline task.icon class="group-hover:stroke-2 size-4 stroke-fg-muted" aria_hidden=true %} {{ task.text|nh3 }} {% if task.type == "Draft" %} - - {{ task.type }} - + {{ task.type }} {% endif %} @@ -28,7 +24,7 @@ datetime="{{ task.created_at|date:'c' }}" prefix="" format-style="narrow" - class="text-sm text-gray-500 group-hover:hidden" + class="text-sm group-hover:hidden text-fg-muted" > {{ task.created_at }} @@ -37,7 +33,7 @@ diff --git a/hypha/apply/translate/forms.py b/hypha/apply/translate/forms.py index d5bd4dd7ca..c1f194246d 100644 --- a/hypha/apply/translate/forms.py +++ b/hypha/apply/translate/forms.py @@ -3,10 +3,10 @@ from hypha.apply.translate.fields import LanguageChoiceField from hypha.apply.translate.utils import get_available_translations +available_packages = get_available_translations() -class TranslateSubmissionForm(forms.Form): - available_packages = get_available_translations() +class TranslateSubmissionForm(forms.Form): from_lang = LanguageChoiceField("from", available_packages) to_lang = LanguageChoiceField("to", available_packages) diff --git a/hypha/apply/translate/management/commands/install_languages.py b/hypha/apply/translate/management/commands/install_languages.py index b927f15fc2..34d0d2d0a9 100644 --- a/hypha/apply/translate/management/commands/install_languages.py +++ b/hypha/apply/translate/management/commands/install_languages.py @@ -6,15 +6,36 @@ class Command(BaseCommand): - help = ( - "Delete all drafts that haven't been modified in the specified time (in days)" - ) + """ + Django management command to install language packages for offline translation support. + + This command provides multiple ways to install Argos Translate language packages: + - Install specific packages by specifying language codes + - Install all available packages with --all flag + - Interactively select packages with --select flag + + Language packages are specified in the format "_" + using ISO 639 language codes (e.g., "en_es" for English to Spanish). + """ + + help = "Install language packages for offline translation support" available_packages = argostranslate.package.get_available_packages() installed_packages = argostranslate.package.get_installed_packages() def __validate_language(self, value): - """Used to validate `from_to_language` argument""" + """ + Validate language package format and availability. + + Args: + value (str): Language package string in format "_" + + Returns: + argostranslate.package.Package: The validated package object + + Raises: + argparse.ArgumentTypeError: If format is invalid or package not available + """ try: from_code, to_code = value.split("_") except ValueError: @@ -38,12 +59,22 @@ def __validate_language(self, value): return package def add_arguments(self, parser): + """ + Add command line arguments for the management command. + + Args: + parser (argparse.ArgumentParser): The argument parser to add arguments to + """ parser.add_argument( "languages", action="store", nargs="*", type=self.__validate_language, - help='Language packages to install in the format of "_" in ISO 639 format', + help=( + 'Language packages to install in the format "_" ' + 'using ISO 639 language codes. Examples: "en_es" (English to Spanish), ' + '"fr_en" (French to English). Multiple packages can be specified.' + ), ) parser.add_argument( @@ -51,34 +82,89 @@ def add_arguments(self, parser): "--no-input", action="store_false", dest="interactive", - help="Do not prompt the user for confirmation", + help="Skip confirmation prompts and install packages automatically", required=False, ) parser.add_argument( "--all", action="store_true", - help="Install all available language packages", + help="Install all available language packages (use with caution - this may install many packages)", + required=False, + ) + + parser.add_argument( + "--select", + action="store_true", + help="Interactively select language packages from a numbered list of available packages", required=False, ) def __print_package_list(self, packages: List[argostranslate.package.Package]): + """ + Print a formatted list of language packages. + + Args: + packages (List[argostranslate.package.Package]): List of packages to display + """ for package in packages: self.stdout.write(f"{package.from_name} ➜ {package.to_name}") + def __select_packages(self): + """ + Interactively select packages from available packages. + + Returns: + List[argostranslate.package.Package]: List of selected packages + + Raises: + argparse.ArgumentTypeError: If user input is invalid + """ + self.stdout.write("Available language packages:") + for i, package in enumerate(self.available_packages): + self.stdout.write(f"{i + 1}. {package.from_name} ➜ {package.to_name}") + + selections = input("\nEnter package numbers (comma-separated) to install: ") + try: + indices = [int(x.strip()) - 1 for x in selections.split(",")] + return [ + self.available_packages[i] + for i in indices + if 0 <= i < len(self.available_packages) + ] + except (ValueError, IndexError) as e: + raise argparse.ArgumentTypeError("Invalid package selection") from e + def handle(self, *args, **options): + """ + Main command execution logic. + + Handles the installation of language packages based on the provided options. + Supports three modes of operation: + 1. Install specific packages by language codes + 2. Install all available packages with --all + 3. Interactive selection with --select + + Args: + *args: Variable length argument list (unused) + **options: Keyword arguments containing parsed command line options + """ interactive = options["interactive"] packages = options["languages"] verbosity = options["verbosity"] all = options["all"] + select = options["select"] - # Require either languages or "--all" to be specified - if not bool(packages) ^ bool(all): + # Determine which packages to install based on command options + if select: + packages = self.__select_packages() + elif not bool(packages) ^ bool(all): raise argparse.ArgumentTypeError("A language selection must be specified") if all: packages = self.available_packages + # Separate packages into already installed and pending installation existing_packages = [ lang for lang in packages if lang in self.installed_packages ] @@ -86,6 +172,7 @@ def handle(self, *args, **options): lang for lang in packages if lang not in self.installed_packages ] + # Report on packages that are already installed if existing_packages: if verbosity > 1: self.stdout.write( @@ -99,9 +186,12 @@ def handle(self, *args, **options): f"The specified package{'s are' if len(existing_packages) > 1 else ' is'} already installed." ) + # Exit early if no packages need installation if not pending_packages: return + # Handle confirmation and installation of pending packages + confirm = "no" if pending_packages: if verbosity > 1: self.stdout.write( @@ -115,17 +205,18 @@ def handle(self, *args, **options): f"{len(pending_packages)} package{'s' if len(pending_packages) > 1 else ''} will be installed." ) + # Get user confirmation if in interactive mode if interactive: - confirm = input( - "Are you sure you want to do this?\n\nType 'yes' to continue, or 'no' to cancel: " - ) + confirm = input("Are you sure you want to do this (y/N)?: ") else: confirm = "yes" - if confirm == "yes": + # Proceed with installation if confirmed + if confirm.lower() in ["yes", "y"]: for package in pending_packages: argostranslate.package.install_from_path(package.download()) + # Calculate and report successful installations successful_installs = len( argostranslate.package.get_installed_packages() ) - len(self.installed_packages) diff --git a/hypha/apply/users/templates/elevate/elevate.html b/hypha/apply/users/templates/elevate/elevate.html index 3ad3d17aad..6e4187e96b 100644 --- a/hypha/apply/users/templates/elevate/elevate.html +++ b/hypha/apply/users/templates/elevate/elevate.html @@ -2,7 +2,7 @@ {% load i18n wagtailcore_tags heroicons %} {% block title %}{% trans "Confirm access" %}{% endblock %} -{% block body_class %}bg-white{% endblock %} +{% block body_class %}bg-base-100{% endblock %} {% block content %}
    @@ -14,38 +14,36 @@

    {% trans "Confirm access" %}

    - - {% if request.user.has_usable_password %} -
    - {% csrf_token %} - {% for field in form %} - {% include "forms/includes/field.html" %} - {% endfor %} - -
    - -
    - - {% else %} -
    - - -
    - {% endif %} + {% csrf_token %} + {% for field in form %} + {% include "forms/includes/field.html" %} + {% endfor %} + + + + {% else %} +
    + +
    + {% endif %} +
    {% if request.user.has_usable_password %}
    diff --git a/hypha/apply/users/templates/two_factor/_base.html b/hypha/apply/users/templates/two_factor/_base.html index c0d6c54a27..76790f57a1 100644 --- a/hypha/apply/users/templates/two_factor/_base.html +++ b/hypha/apply/users/templates/two_factor/_base.html @@ -1,27 +1,25 @@ {% extends 'base-apply.html' %} {% load i18n static heroicons %} -{% block content %} - {% adminbar %} - - {% slot back_link %} - {% trans "Back to Account" %} - {% endslot %} - - {% slot header %} - {% trans "Two-Factor Authentication (2FA)" %} - {% endslot %} - {% comment %} {% slot sub_heading %}{% trans "All submissions ready for discussion." %}{% endslot %} {% endcomment %} - - {% if user.can_access_dashboard %} - - {% heroicon_mini "squares-2x2" size=20 class="inline mr-1 align-text-bottom" %} - {% trans "Go to my dashboard" %} - - {% endif %} - {% endadminbar %} +{% block hero %} + + + {% if user.can_access_dashboard %} + + {% heroicon_mini "squares-2x2" size=20 class="inline mr-1 align-text-bottom" %} + {% trans "Go to my dashboard" %} + + {% endif %} + + +{% endblock %} -
    +{% block content %} +
    {% block content_inner %}{% endblock %}
    {% endblock %} diff --git a/hypha/apply/users/templates/two_factor/_wizard_actions.html b/hypha/apply/users/templates/two_factor/_wizard_actions.html index 182bbf53df..3e81b97c65 100644 --- a/hypha/apply/users/templates/two_factor/_wizard_actions.html +++ b/hypha/apply/users/templates/two_factor/_wizard_actions.html @@ -10,22 +10,16 @@ {% trans "Next" as button_text %} {% endif %} - + diff --git a/hypha/apply/users/templates/two_factor/admin/disable.html b/hypha/apply/users/templates/two_factor/admin/disable.html index b05335d82e..73e389c7db 100644 --- a/hypha/apply/users/templates/two_factor/admin/disable.html +++ b/hypha/apply/users/templates/two_factor/admin/disable.html @@ -19,7 +19,7 @@ {% endblock %}
  • - +
  • diff --git a/hypha/apply/users/templates/two_factor/core/backup_tokens.html b/hypha/apply/users/templates/two_factor/core/backup_tokens.html index 6f1eb96e3e..ee2a181076 100644 --- a/hypha/apply/users/templates/two_factor/core/backup_tokens.html +++ b/hypha/apply/users/templates/two_factor/core/backup_tokens.html @@ -1,51 +1,73 @@ {% extends "two_factor/_base.html" %} -{% load static i18n users_tags %} +{% load static i18n users_tags heroicons %} {% block content_inner %} -

    {% block title %}{% trans "Backup Codes" %}{% endblock %}

    +

    + {% block title %}{% trans "Backup Codes" %}{% endblock %} +

    -

    +

    {% blocktrans %}You should now print these codes or copy them to your clipboard and store them in your password manager.{% endblocktrans %}

    {% if device.token_set.count %} - - {% csrf_token %}{{ form }} -

    - {% trans "Print" %} - {% trans "Copy to Clipboard" %} - -

    + {% csrf_token %}{{ form }} +
    + + + {% heroicon_mini "clipboard" class="size-4" aria_hidden="true" %} + {% trans "Copy to Clipboard" %} + + +
    -

    {% blocktrans trimmed %} Note: Each of the code can be used only once. When they are used up, you can generate a new set of backup codes.{% endblocktrans %}

    -

    {% blocktrans %}Once done, acknowledge you have stored the codes securely and then click "Finish".{% endblocktrans %}

    -
    - -
    - +

    + {% blocktrans trimmed %} Note: Each of the code can be used only once. When they are used up, you can generate a new set of backup codes.{% endblocktrans %} +

    +

    + {% blocktrans %}Once done, acknowledge you have stored the codes securely and then click "Finish".{% endblocktrans %} +

    +
    + +
    +
    - {% else %} -

    {% trans "You don't have any backup codes yet." %}

    +

    + {% trans "You don't have any backup codes yet." %} +

    {% csrf_token %}{{ form }} @@ -55,9 +77,7 @@

    {% block title %}{% trans "Backup Codes" %}{% endblock %}

    {% block extra_css %} {% endblock %} @@ -65,46 +85,24 @@

    {% block title %}{% trans "Backup Codes" %}{% endblock %}

    {% block extra_js %} {% endblock %} diff --git a/hypha/apply/users/templates/two_factor/core/backup_tokens_password.html b/hypha/apply/users/templates/two_factor/core/backup_tokens_password.html index 752529d66b..10f1ef5265 100644 --- a/hypha/apply/users/templates/two_factor/core/backup_tokens_password.html +++ b/hypha/apply/users/templates/two_factor/core/backup_tokens_password.html @@ -10,7 +10,7 @@

    {% block title %}{% trans "Backup Codes" %}{% endblock %}


    These codes should be kept in a secure, private place (print them or store them in your password manager) for when you need them. When they are used up, you can generate a new set of backup codes.{% endblocktrans %}

    -
    +
    {% if form.non_field_errors %}
      @@ -36,9 +36,7 @@

      {% block title %}{% trans "Backup Codes" %}{% endblock %}

      {% include "forms/includes/field.html" %} {% endfor %} -
      - -
      +
    {% endblock %} diff --git a/hypha/apply/users/templates/two_factor/core/setup.html b/hypha/apply/users/templates/two_factor/core/setup.html index 9ceb5b61c0..7b7ea304a4 100644 --- a/hypha/apply/users/templates/two_factor/core/setup.html +++ b/hypha/apply/users/templates/two_factor/core/setup.html @@ -2,52 +2,53 @@ {% load i18n %} {% block content_inner %} - {% if wizard.steps.current == 'welcome' %} -

    {% blocktrans trimmed %}2FA is an extra layer of security used to make sure that people trying to gain access to an - online account are who they say they are. We recommend using Authy or another - authenticator app.{% endblocktrans %}

    -

    {% blocktrans trimmed %}Please contact {{ ORG_EMAIL }} if you have technical difficulty - enabling 2FA.{% endblocktrans %}

    - {% elif wizard.steps.current == 'method' %} -

    {% blocktrans trimmed %}Please select which authentication method you would - like to use.{% endblocktrans %}

    - {% elif wizard.steps.current == 'generator' %} -

    {% blocktrans trimmed %}2FA requires a verification code to pair your smartphone with your account. - {% endblocktrans %}

    -

    {% blocktrans trimmed %}Step 1: Open the Authenticator app on your phone and scan the QR code displayed below. - {% endblocktrans %}

    -

    QR Code

    -

    {% trans "Unable to scan the QR code? Try this link:" %} {{ otpauth_url }}

    -

    {% blocktrans trimmed %}Step 2: Enter the 6-digit verification code generated by the app below.{% endblocktrans %}

    - {% elif wizard.steps.current == 'sms' %} -

    {% blocktrans trimmed %}Please enter the phone number you wish to receive the - text messages on. This number will be validated in the next step. - {% endblocktrans %}

    - {% elif wizard.steps.current == 'call' %} -

    {% blocktrans trimmed %}Please enter the phone number you wish to be called on. - This number will be validated in the next step. {% endblocktrans %}

    - {% elif wizard.steps.current == 'validation' %} - {% if challenge_succeeded %} - {% if device.method == 'call' %} -

    {% blocktrans trimmed %}We are calling your phone right now, please enter the - digits you hear.{% endblocktrans %}

    - {% elif device.method == 'sms' %} -

    {% blocktrans trimmed %}We sent you a text message, please enter the tokens we - sent.{% endblocktrans %}

    +
    + {% if wizard.steps.current == 'welcome' %} +

    {% blocktrans trimmed %}2FA is an extra layer of security used to make sure that people trying to gain access to an + online account are who they say they are. We recommend using Authy or another + authenticator app.{% endblocktrans %}

    +

    {% blocktrans trimmed %}Please contact {{ ORG_EMAIL }} if you have technical difficulty + enabling 2FA.{% endblocktrans %}

    + {% elif wizard.steps.current == 'method' %} +

    {% blocktrans trimmed %}Please select which authentication method you would + like to use.{% endblocktrans %}

    + {% elif wizard.steps.current == 'generator' %} +

    {% blocktrans trimmed %}2FA requires a verification code to pair your smartphone with your account. + {% endblocktrans %}

    +

    {% blocktrans trimmed %}Step 1: Open the Authenticator app on your phone and scan the QR code displayed below. + {% endblocktrans %}

    +

    QR Code

    +

    {% trans "Unable to scan the QR code? Try this link:" %} {{ otpauth_url }}

    +

    {% blocktrans trimmed %}Step 2: Enter the 6-digit verification code generated by the app below.{% endblocktrans %}

    + {% elif wizard.steps.current == 'sms' %} +

    {% blocktrans trimmed %}Please enter the phone number you wish to receive the + text messages on. This number will be validated in the next step. + {% endblocktrans %}

    + {% elif wizard.steps.current == 'call' %} +

    {% blocktrans trimmed %}Please enter the phone number you wish to be called on. + This number will be validated in the next step. {% endblocktrans %}

    + {% elif wizard.steps.current == 'validation' %} + {% if challenge_succeeded %} + {% if device.method == 'call' %} +

    {% blocktrans trimmed %}We are calling your phone right now, please enter the + digits you hear.{% endblocktrans %}

    + {% elif device.method == 'sms' %} +

    {% blocktrans trimmed %}We sent you a text message, please enter the tokens we + sent.{% endblocktrans %}

    + {% endif %} + {% else %} + {% endif %} - {% else %} - + {% elif wizard.steps.current == 'yubikey' %} +

    {% blocktrans trimmed %}To identify and verify your YubiKey, please insert a + token in the field below. Your YubiKey will be linked to your + account.{% endblocktrans %}

    {% endif %} - {% elif wizard.steps.current == 'yubikey' %} -

    {% blocktrans trimmed %}To identify and verify your YubiKey, please insert a - token in the field below. Your YubiKey will be linked to your - account.{% endblocktrans %}

    - {% endif %} - +
    {% csrf_token %} {% include "two_factor/_wizard_forms.html" %} diff --git a/hypha/apply/users/templates/two_factor/core/setup_complete.html b/hypha/apply/users/templates/two_factor/core/setup_complete.html index 4418bf69d9..d0f29a33bc 100644 --- a/hypha/apply/users/templates/two_factor/core/setup_complete.html +++ b/hypha/apply/users/templates/two_factor/core/setup_complete.html @@ -3,29 +3,33 @@ {% block content_inner %} -
    -

    {% blocktrans trimmed %}Congratulations, you've successfully enabled two-factor - authentication.{% endblocktrans %}

    - -

    {% blocktrans trimmed %}We strongly recommend you to save the backup codes. - To get the backup codes you can continue to Show Codes.{% endblocktrans %}

    -
    - - {% if not phone_methods %} - {% trans "Show Codes" %} - - {% else %} -

    {% blocktrans trimmed %}However, it might happen that you don't have access to - your primary token device. To enable account recovery, add a phone - number.{% endblocktrans %}

    - -

    {% trans "Show Codes" %}

    - -

    - {% trans "Add Phone Number" %} - -

    - {% endif %} +
    +

    {% blocktrans trimmed %}Congratulations, you've successfully enabled two-factor + authentication.{% endblocktrans %}

    + +

    {% blocktrans trimmed %}We strongly recommend you to save the backup codes. + To get the backup codes you can continue to Show Codes.{% endblocktrans %}

    + + {% if phone_methods %} +

    {% blocktrans trimmed %}However, it might happen that you don't have access to + your primary token device. To enable account recovery, add a phone + number.{% endblocktrans %}

    + + + + {% else %} + + {% trans "Show Codes" %} + + {% endif %} +
    {% endblock %} diff --git a/hypha/apply/users/templates/users/account.html b/hypha/apply/users/templates/users/account.html index fee2acb503..60b80fceef 100644 --- a/hypha/apply/users/templates/users/account.html +++ b/hypha/apply/users/templates/users/account.html @@ -3,70 +3,77 @@ {% block title %}{% trans "Account" %}{% endblock %} -{% block content %} - {% adminbar %} - {% slot header %}{% trans "Welcome" %} {{ user }}{% endslot %} - {% slot sub_heading %}{% trans "Manage your account details and security." %}{% endslot %} - - - {% if user.can_access_dashboard %} - - {% heroicon_mini "squares-2x2" size=20 class="inline align-text-bottom me-1" aria_hidden=true %} - {% trans "Go to my dashboard" %} - - {% else %} -
    -
    -

    {% trans "Submit a new application" %}

    -

    {% trans "Apply now for our open rounds" %}

    -
    -
    - {% trans "Apply" %} +{% block hero %} + + + + {% if user.can_access_dashboard %} + + {% heroicon_mini "squares-2x2" size=20 class="opacity-80" aria_hidden=true %} + {% trans "Go to my dashboard" %} + + {% else %} +
    +
    +

    {% trans "Submit a new application" %}

    +

    {% trans "Apply now for our open rounds" %}

    +
    +
    -
    - {% endif %} - {% if perms.wagtailadmin.access_admin %} - - {% heroicon_solid "cog-6-tooth" size=20 class="inline align-text-bottom me-1" aria_hidden=true %} - {% trans "Administration" %} - - {% endif %} - - {% endadminbar %} + {% endif %} + {% if perms.wagtailadmin.access_admin %} + + {% heroicon_solid "cog-6-tooth" size=20 class="opacity-80" aria_hidden=true %} + {% trans "Administration" %} + + {% endif %} + + + +{% endblock %} +{% block content %}
    -

    {% trans "Profile" %}

    +

    {% trans "Profile" %}

    {% csrf_token %} {% for field in form %} {% include "forms/includes/field.html" %} {% endfor %} -
    - -
    +
    -
    -

    {% trans "Account Security" %}

    +

    {% trans "Account Security" %}

    {% if show_change_password %}
    -

    {% trans "Password" %}

    +

    {% trans "Password" %}

    {% if user.has_usable_password %} - + + {% heroicon_micro "key" class="inline size-4" aria_hidden=true %} {% trans "Update password" %} {% else %} - {% endif %} @@ -74,15 +81,17 @@

    {% trans "Password" %}

    {% endif %} -

    {% trans "Two-Factor Authentication (2FA)" %}

    -
    +

    + {% trans "Two-Factor Authentication (2FA)" %} +

    +

    {% if default_device %} - {% trans "Backup codes" %} - {% trans "Disable 2FA" %} + {% trans "Backup codes" %} + {% trans "Disable 2FA" %} {% else %} - {% trans "Enable 2FA" %} + {% trans "Enable 2FA" %} {% endif %} -

    +

    {# Remove the comment block tags below when such need arises. e.g. adding new providers #} {% comment %} diff --git a/hypha/apply/users/templates/users/activation/invalid.html b/hypha/apply/users/templates/users/activation/invalid.html index 39435b2fb4..32333da7b2 100644 --- a/hypha/apply/users/templates/users/activation/invalid.html +++ b/hypha/apply/users/templates/users/activation/invalid.html @@ -1,25 +1,30 @@ {% extends "base-apply.html" %} {% load i18n heroicons %} -{% block title %}{% trans "Invalid activation" %}{% endblock %} -{% block body_class %}bg-white{% endblock %} +{% block title %}{% trans "Activation link issue" %}{% endblock %} +{% block body_class %}bg-base-200{% endblock %} {% block content %} -
    +
    +
    +
    + + {% heroicon_outline "exclamation-triangle" class="w-14 h-14 text-warning" %} + -
    - {% heroicon_outline "exclamation-triangle" aria_hidden="true" size=64 class="stroke-red-600" %} +

    {% trans "We couldn't activate your account" %}

    -

    {% trans "Invalid activation URL" %}

    - {% url 'users:password_reset' as password_reset %} -
    -

    {% trans "Two possible reasons:" %}

    -
      -
    1. {% trans "The activation link has expired." %}
    2. -
    3. {% trans "The account has already been activated." %}
    4. -
    +
    + {% url 'users:password_reset' as password_reset %} -

    {% blocktrans %}First try to reset your password. If that fails please contact {{ ORG_SHORT_NAME }} at{% endblocktrans %} {{ ORG_EMAIL }}

    -
    -
    +

    {% trans "This usually happens because your activation link has expired, or your account is already activated." %}

    + +

    + {% blocktrans %}Try resetting your password first. If you're still having trouble, contact us at {{ ORG_SHORT_NAME }}:{% endblocktrans %} + {{ ORG_EMAIL }} +

    +
    +
    +
    +
    {% endblock %} diff --git a/hypha/apply/users/templates/users/become.html b/hypha/apply/users/templates/users/become.html index 7561b9e741..d611266668 100644 --- a/hypha/apply/users/templates/users/become.html +++ b/hypha/apply/users/templates/users/become.html @@ -1,6 +1,6 @@ {% load i18n static %} -{% modal_title %}{% trans "Switch to User..." %}{% endmodal_title %} +{% trans "Switch to User..." %}
    {% csrf_token %} @@ -18,9 +18,9 @@ {{ form.user_pk.help_text }}

    -
    +
    diff --git a/hypha/apply/users/templates/users/change_password.html b/hypha/apply/users/templates/users/change_password.html index e5505cc388..8c2acf599d 100644 --- a/hypha/apply/users/templates/users/change_password.html +++ b/hypha/apply/users/templates/users/change_password.html @@ -2,19 +2,19 @@ {% load i18n %} {% block title %}{% trans "Update password" %}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "Change Password" %}{% endslot %} - {% slot back %} - - {% trans "Back to account" %} - - {% endslot %} - {% endadminbar %} +{% block hero %} + + + +{% endblock %} -
    - +{% block content %} +
    + {% if redirect_url %} {% endif %} @@ -42,9 +42,7 @@ {% include "forms/includes/field.html" %} {% endfor %} -
    - -
    +
    {% endblock %} diff --git a/hypha/apply/users/templates/users/email_change/done.html b/hypha/apply/users/templates/users/email_change/done.html index d660d81941..787efd4b65 100644 --- a/hypha/apply/users/templates/users/email_change/done.html +++ b/hypha/apply/users/templates/users/email_change/done.html @@ -3,14 +3,15 @@ {% block page_title %}{% trans "Email Change - Verify Email" %}{% endblock %} {% block title %}{% trans "Verify Email" %}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "Email Update" %}{% endslot %} - {% endadminbar %} +{% block hero %} + + + +{% endblock %} -
    -

    {% trans "Confirm & verify your new email!" %}

    +{% block content %} +
    +

    {% trans "Confirm & verify your new email!" %}

    {% trans "We have sent a confirmation link to your new email." %}

    diff --git a/hypha/apply/users/templates/users/email_change/invalid_link.html b/hypha/apply/users/templates/users/email_change/invalid_link.html index fa11dccc65..b9debf1b9a 100644 --- a/hypha/apply/users/templates/users/email_change/invalid_link.html +++ b/hypha/apply/users/templates/users/email_change/invalid_link.html @@ -1,16 +1,25 @@ -{% extends 'base.html' %} -{% load i18n %} +{% extends "base-apply.html" %} +{% load i18n heroicons %} {% block title %}{% trans "Invalid Confirmation" %}{% endblock %} -{% block page_title %}{% trans "Invalid Confirmation URL" %}{% endblock %} +{% block body_class %}bg-base-200{% endblock %} {% block content %} -
    -

    {% trans "Possible reason:" %}

    -
      -
    • {% trans "The confirmation link has expired." %}
    • -
    +
    +
    +
    + + {% heroicon_outline "exclamation-triangle" class="w-14 h-14 text-warning" %} + -

    {% blocktrans %}Try again to change email from accounts page. If that fails please contact {{ ORG_SHORT_NAME }} at{% endblocktrans %} {{ ORG_EMAIL }}

    +

    {% trans "Invalid Confirmation URL" %}

    + +
    +

    {% trans "The confirmation link you used is either invalid or has expired." %}

    + +

    {% blocktrans %}Try again to change email from accounts page. If that fails please contact {{ ORG_SHORT_NAME }} at{% endblocktrans %} {{ ORG_EMAIL }}

    +
    +
    +
    {% endblock %} diff --git a/hypha/apply/users/templates/users/login.html b/hypha/apply/users/templates/users/login.html index 38bb43700f..7f69b8ceae 100644 --- a/hypha/apply/users/templates/users/login.html +++ b/hypha/apply/users/templates/users/login.html @@ -2,10 +2,9 @@ {% load i18n wagtailcore_tags heroicons %} {% block title %}{% trans "Log in" %}{% endblock %} -{% block body_class %}bg-white{% endblock %} {% block content %} -
    +
    @@ -44,38 +43,43 @@

    {% trans "Two factor verification" %}

    {% blocktrans %}Log in to {{ ORG_SHORT_NAME }}{% endblocktrans %}

    {% for field in form %} -
    +
    {% include "forms/includes/field.html" %} {% if field.auto_id == "id_auth-password" %} {% endif %}
    {% endfor %} {% if settings.users.AuthSettings.extra_text %} -
    +
    {{ settings.users.AuthSettings.extra_text|richtext }}
    {% endif %} -
    - +
    +
    -
    -
    - {% trans "or" %} -
    -
    +
    {% translate "OR" %}
    -
    +
    {% if GOOGLE_OAUTH2 %} {% include "includes/org_login_button.html" %} {% endif %} {% include "includes/passwordless_login_button.html" %} -
    + {% else %}
    @@ -93,10 +97,11 @@

    {% blocktrans %}Log in to {{ ORG_SHORT_NAME }}{% endblocktr class="btn btn-default btn-block" type="submit"> {{ other.generate_challenge_button_title }} - {% endfor %}

    + {% endfor %} +

    {% endif %} -
    +
    {% include "two_factor/_wizard_actions.html" %}
    @@ -107,7 +112,7 @@

    {% blocktrans %}Log in to {{ ORG_SHORT_NAME }}{% endblocktr type="submit" value="backup" aria-label="Click here to use a backup code" - class="inline font-bold transition-opacity hover:opacity-70 text-dark-blue" + class="font-semibold link link-primary" > {% trans "Use a Backup Code" %} diff --git a/hypha/apply/users/templates/users/partials/confirmation_code_sent.html b/hypha/apply/users/templates/users/partials/confirmation_code_sent.html index 4a7403646e..988ac8e972 100644 --- a/hypha/apply/users/templates/users/partials/confirmation_code_sent.html +++ b/hypha/apply/users/templates/users/partials/confirmation_code_sent.html @@ -1,6 +1,6 @@ {% load i18n heroicons %}
    @@ -23,7 +23,7 @@ required type='text' maxlength='6' - class="mb-2 w-28! placeholder:text-gray-400 text-center tracking-wider" + class="mb-2 w-28! placeholder:text-fg-muted text-center tracking-wider" x-model="code" autocomplete="off" placeholder="_ _ _ _ _ _" @@ -33,7 +33,7 @@

    {% endif %} - diff --git a/hypha/apply/users/templates/users/password_reset/complete.html b/hypha/apply/users/templates/users/password_reset/complete.html index 98dec30d53..9dd826e69d 100644 --- a/hypha/apply/users/templates/users/password_reset/complete.html +++ b/hypha/apply/users/templates/users/password_reset/complete.html @@ -2,13 +2,14 @@ {% load i18n %} {% block title %}{% trans "Reset password" %}{% endblock %} -{% block content %} - - {% adminbar %} - {% slot header %}{% trans "Password change successful" %}{% endslot %} - {% endadminbar %} +{% block hero %} + + + +{% endblock %} -
    +{% block content %} +

    {% trans "Log in" %}

    diff --git a/hypha/apply/users/templates/users/password_reset/confirm.html b/hypha/apply/users/templates/users/password_reset/confirm.html index 29db9609a5..61b0653931 100644 --- a/hypha/apply/users/templates/users/password_reset/confirm.html +++ b/hypha/apply/users/templates/users/password_reset/confirm.html @@ -1,11 +1,11 @@ {% extends "base-apply.html" %} {% load i18n %} {% block title %}{{ title }}{% endblock %} -{% block body_class %}bg-white{% endblock %} +{% block body_class %}bg-base-100{% endblock %} {% block content %} -
    +
    {% if validlink %}

    {% trans "Reset password" %}

    @@ -39,7 +39,7 @@

    {% trans "Reset password" %}

    {% include "forms/includes/field.html" %} {% endfor %} - + {% else %}

    {% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}

    diff --git a/hypha/apply/users/templates/users/password_reset/done.html b/hypha/apply/users/templates/users/password_reset/done.html index 9b85d98ae9..f2993904f6 100644 --- a/hypha/apply/users/templates/users/password_reset/done.html +++ b/hypha/apply/users/templates/users/password_reset/done.html @@ -2,11 +2,11 @@ {% load i18n %} {% block title %}{% trans "Password Reset" %}{% endblock %} -{% block body_class %}bg-white{% endblock %} +{% block body_class %}bg-base-100{% endblock %} {% block content %} -
    +

    {% trans "Check your inbox for a password reset email!" %} diff --git a/hypha/apply/users/templates/users/password_reset/form.html b/hypha/apply/users/templates/users/password_reset/form.html index 635bc77c8c..d9817895a3 100644 --- a/hypha/apply/users/templates/users/password_reset/form.html +++ b/hypha/apply/users/templates/users/password_reset/form.html @@ -2,41 +2,29 @@ {% load i18n %} {% block title %}{% trans "Reset password" %}{% endblock %} -{% block body_class %}bg-white{% endblock %} {% block content %} -
    -
    -

    {% trans "Forgot password?" %}

    -

    {% trans "Please enter your user account's email address and we will send you a password reset link." %}

    +
    + + {% csrf_token %} +

    {% trans "Forgot password?" %}

    +

    + {% trans "Please enter your user account's email address and we will send you a password reset link." %} +

    + {% if redirect_url %} {% endif %} - {% if form.non_field_errors %} -
      - {% for error in form.non_field_errors %} -
    • {{ error }}
    • - {% endfor %} -
    - {% endif %} - - {% if form.errors %} -
      - {% blocktrans trimmed count counter=form.errors.items|length %} -
    • Please correct the error below.
    • - {% plural %} -
    • Please correct the errors below.
    • - {% endblocktrans %} -
    - {% endif %} - -

    {{ form.email.label_tag }}

    -

    {{ form.email }}

    + {% for field in form %} + {% include "forms/includes/field.html" %} + {% endfor %} - +
    {% endblock %} diff --git a/hypha/apply/users/templates/users/passwordless_login_signup.html b/hypha/apply/users/templates/users/passwordless_login_signup.html index 374c92a28f..27fe7752f4 100644 --- a/hypha/apply/users/templates/users/passwordless_login_signup.html +++ b/hypha/apply/users/templates/users/passwordless_login_signup.html @@ -6,7 +6,7 @@ {% endblock %} {% block content %} -
    +
    @@ -38,22 +38,18 @@

    {% if settings.users.AuthSettings.extra_text %} -
    +
    {{ settings.users.AuthSettings.extra_text|richtext }}
    {% endif %} -
    - +
    +
    -
    -
    - {% trans "or" %} -
    -
    +
    {% translate "OR" %}
    -
    +
    {% if GOOGLE_OAUTH2 %} {% include "includes/org_login_button.html" %} {% endif %} diff --git a/hypha/apply/users/templates/users/register-success.html b/hypha/apply/users/templates/users/register-success.html index 5aa80e9d47..557aa77d29 100644 --- a/hypha/apply/users/templates/users/register-success.html +++ b/hypha/apply/users/templates/users/register-success.html @@ -2,11 +2,11 @@ {% load i18n heroicons %} {% block title %}{% trans "Register" %}{% endblock %} -{% block body_class %}bg-white{% endblock %} +{% block body_class %}bg-base-100{% endblock %} {% block content %} -
    +
    {% heroicon_outline "document-check" aria_hidden="true" size=64 %} diff --git a/hypha/apply/utils/templatetags/apply_tags.py b/hypha/apply/utils/templatetags/apply_tags.py index 7e11011a68..f9be602888 100644 --- a/hypha/apply/utils/templatetags/apply_tags.py +++ b/hypha/apply/utils/templatetags/apply_tags.py @@ -67,5 +67,5 @@ def truncatechars_middle(value, arg): @register.simple_tag -def primary_navigation_items(user): - return get_primary_navigation_items(user) +def primary_navigation_items(request): + return get_primary_navigation_items(request) diff --git a/hypha/cookieconsent/static/js/cookieconsent.js b/hypha/cookieconsent/static/js/cookieconsent.js index a9306f9d81..daf83cf784 100644 --- a/hypha/cookieconsent/static/js/cookieconsent.js +++ b/hypha/cookieconsent/static/js/cookieconsent.js @@ -1,31 +1,10 @@ (function () { - // Used when an analytics cookie notice is enabled const ACCEPT = "accept"; const DECLINE = "decline"; const ACK = "ack"; // Only for essential cookies - // Constant key used for localstorage const COOKIECONSENT_KEY = "cookieconsent"; - // Class constants - const CLASS_COOKIECONSENT = "cookieconsent"; - const CLASS_LEARNMORE = "cookieconsent__learnmore"; - const CLASS_COOKIEBRIEF = "cookieconsent__brief"; - const CLASS_COOKIECONTENT = "cookieconsent__content"; - const CLASS_JS_CONSENT_OPEN = "js-cookieconsent-open"; - const CLASS_JS_LEARNMORE = "js-cookieconsent-show-learnmore"; - const CLASS_JS_LEARNMORE_EXPAND = `${CLASS_JS_LEARNMORE}-expand`; - - const cookieconsent = document.querySelector(`.${CLASS_COOKIECONSENT}`); - if (!cookieconsent) { - return; - } - - const cookieButtons = cookieconsent.querySelectorAll("button[data-consent]"); - const learnMoreToggles = cookieconsent.querySelectorAll( - ".button--learn-more" - ); - /** * Pull the cookie consent value from localStorage * @@ -49,74 +28,53 @@ } } - /** - * Trigger the cookie consent prompt to open - */ - function openConsentPrompt() { - cookieconsent.classList.add(CLASS_JS_CONSENT_OPEN); - } + document.addEventListener("alpine:init", () => { + Alpine.data("cookieConsent", () => ({ + isOpen: false, + showLearnMore: false, - /** - * Trigger cookie consent prompt to close - */ - function closeConsentPrompt() { - cookieconsent.classList.remove(CLASS_JS_CONSENT_OPEN); - } + init() { + const consentValue = getConsentValue(); + const cookieButtons = this.$el.querySelectorAll("button[data-consent]"); - // Expose consent prompt opening/closing globally (ie. to use in a footer) - window.openConsentPrompt = openConsentPrompt; - window.closeConsentPrompt = closeConsentPrompt; + // Open the prompt if consent value is undefined OR if analytics has been added since the user ack'd essential cookies + if ( + consentValue == null || + (consentValue === ACK && cookieButtons.length > 2) + ) { + this.openConsentPrompt(); + } - /** - * Trigger the "Learn More" prompt on the cookie banner to open/close - * - * @param {boolean} open - true to open learn more prompt, false to close - */ - function toggleLearnMore(open) { - const content = cookieconsent.querySelector(`.${CLASS_COOKIECONTENT}`); - if (open) { - content.classList.add(CLASS_JS_LEARNMORE); - cookieconsent.classList.add(CLASS_JS_LEARNMORE_EXPAND); - } else { - content.classList.remove(CLASS_JS_LEARNMORE); - cookieconsent.classList.remove(CLASS_JS_LEARNMORE_EXPAND); - } - setInputTabIndex(`.${CLASS_LEARNMORE}`, open ? 0 : -1); - setInputTabIndex(`.${CLASS_COOKIEBRIEF}`, open ? -1 : 0); - } + cookieButtons.forEach((button) => { + button.addEventListener("click", () => { + const buttonValue = button.getAttribute("data-consent"); + this.handleConsent(buttonValue); + }); + }); - /** - * Adds "tabability" to menu buttons/toggles - * - * @param {string} wrapperClassSelector - wrapper class to set tabability of inputs on - * @param {number} tabValue - tab index value to set on all input items in the wrapper class - */ - function setInputTabIndex(wrapperClassSelector, tabValue) { - const wrapper = cookieconsent.querySelector(wrapperClassSelector); - const tabables = wrapper.querySelectorAll("button, input"); - tabables.forEach((element) => (element.tabIndex = tabValue)); - } + // Expose methods globally for external use (ie. footer links) + window.openConsentPrompt = () => this.openConsentPrompt(); + window.closeConsentPrompt = () => this.closeConsentPrompt(); + }, - // Open the prompt if consent value is undefined OR if analytics has been added since the user ack'd essential cookies - if ( - getConsentValue() == null || - (getConsentValue() === ACK && cookieButtons.length > 2) - ) { - openConsentPrompt(); - } + openConsentPrompt() { + this.isOpen = true; + this.showLearnMore = false; + }, - cookieButtons.forEach(function (button) { - button.addEventListener("click", function () { - const buttonValue = button.getAttribute("data-consent"); - setConsentValue(buttonValue); - closeConsentPrompt(); - }); - }); + closeConsentPrompt() { + this.isOpen = false; + this.showLearnMore = false; + }, + + handleConsent(value) { + setConsentValue(value); + this.closeConsentPrompt(); + }, - learnMoreToggles.forEach(function (button) { - button.addEventListener("click", function () { - const buttonValue = button.getAttribute("show-learn-more"); - toggleLearnMore(buttonValue === "true"); - }); + toggleLearnMore() { + this.showLearnMore = !this.showLearnMore; + }, + })); }); })(); diff --git a/hypha/cookieconsent/templates/includes/banner.html b/hypha/cookieconsent/templates/includes/banner.html index 47392748c4..8db2c76c3d 100644 --- a/hypha/cookieconsent/templates/includes/banner.html +++ b/hypha/cookieconsent/templates/includes/banner.html @@ -1,93 +1,99 @@ -{% load i18n wagtailcore_tags %} +{% load i18n wagtailcore_tags heroicons %} -{% if show_banner %} -
    -
    -
    -
    -

    - {% trans settings.cookieconsent_title %} -

    -
    - {{ settings.cookieconsent_message|richtext }} -
    - -
    - {% if settings.cookieconsent_analytics %} - - - - {% else %} - - {% endif %} - - - -
    +{% if settings.cookieconsent_active %} + {% endif %} diff --git a/hypha/cookieconsent/templatetags/cookieconsent_tags.py b/hypha/cookieconsent/templatetags/cookieconsent_tags.py index bd18fc35c4..a2ee9b9d55 100644 --- a/hypha/cookieconsent/templatetags/cookieconsent_tags.py +++ b/hypha/cookieconsent/templatetags/cookieconsent_tags.py @@ -7,10 +7,4 @@ @register.inclusion_tag("includes/banner.html", takes_context=True) def cookie_banner(context): - request = context["request"] - settings = CookieConsentSettings.load(request_or_site=request) - show_banner = settings.cookieconsent_active and not request.COOKIES.get( - "cookieconsent" - ) - - return {"show_banner": show_banner, "settings": settings} + return {"settings": CookieConsentSettings.load(request_or_site=context["request"])} diff --git a/hypha/core/apps.py b/hypha/core/apps.py index ecc488a2c3..0e76f9a20a 100644 --- a/hypha/core/apps.py +++ b/hypha/core/apps.py @@ -8,5 +8,4 @@ class CoreAppConfig(AppConfig): def ready(self): from . import components # noqa - component.register("adminbar", component=components.AdminBar) component.register("dropdown_menu", component=components.DropdownMenu) diff --git a/hypha/core/components.py b/hypha/core/components.py index 06ba163ecd..189995acc9 100644 --- a/hypha/core/components.py +++ b/hypha/core/components.py @@ -3,16 +3,6 @@ from django_web_components import component -@component.register("admin_bar") -class AdminBar(component.Component): - template_name = "components/admin_bar.html" - - -@component.register("modal_title") -class ModalTitle(component.Component): - template_name = "components/modal-title.html" - - @component.register("dropdown-item") class DropdownMenu(component.Component): template_name = "components/dropdown-menu.html" diff --git a/hypha/core/navigation.py b/hypha/core/navigation.py index 2e5b0fc0b9..5d2dcaed47 100644 --- a/hypha/core/navigation.py +++ b/hypha/core/navigation.py @@ -1,33 +1,54 @@ import copy import functools import importlib +import logging +import re from django.conf import settings from django.core.exceptions import PermissionDenied from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ +logger = logging.getLogger(__name__) -def _check_permission(user, method: str) -> bool: + +def _check_permission(user, method_path: str) -> bool: """Resolve the method path and check if the user has permission. Args: user: user object - method: import path to the method to check permission + method_path: import path to the method to check permission Returns: bool: True if user has permission, False otherwise """ - module = importlib.import_module(method.rsplit(".", 1)[0]) - method = method.rsplit(".", 1)[1] try: - return getattr(module, method)(user) + module_name, method_name = method_path.rsplit(".", 1) + module = importlib.import_module(module_name) + actual_method = getattr(module, method_name) + return actual_method(user) except PermissionDenied: return False + except (ImportError, AttributeError, ValueError) as e: + logger.warning( + f"Permission check failed for method '{method_path}': {e}", exc_info=True + ) + return False + + +def _calculate_is_active( + item_url: str, item_active_regex: str | None, current_path: str +) -> bool: + """Helper to determine if a nav item is active based on URL or regex.""" + if str(item_url) == current_path: + return True + if item_active_regex: + return bool(re.match(item_active_regex, current_path)) + return False @functools.cache -def get_primary_navigation_items(user): +def get_primary_navigation_items(request): DEFAULT_NAV_ITEMS = [ { "title": _("My Dashboard"), @@ -36,9 +57,9 @@ def get_primary_navigation_items(user): }, { "title": _("Submissions"), - # kind of basic url to figure out active tab "url": reverse_lazy("apply:submissions:list"), "permission_method": "hypha.apply.users.decorators.is_apply_staff_or_reviewer_required", + "active_url_regex": r"^(.*)/submissions/(?!.*project)", "sub_items": [ { "title": _("All Submissions"), @@ -75,9 +96,9 @@ def get_primary_navigation_items(user): }, { "title": _("Projects"), - # kind of basic url to figure out active tab "url": reverse_lazy("apply:projects:all"), "permission_method": "hypha.apply.users.decorators.is_apply_staff_or_finance_or_contracting", + "active_url_regex": r"(.*)/projects?/", "sub_items": [ { "title": _("All Projects"), @@ -104,25 +125,46 @@ def get_primary_navigation_items(user): ) nav_items = [] + request_path = request.path for item in original_nav_items: nav_item = item.copy() - if item["title"] == "Projects" and not settings.PROJECTS_ENABLED: + if nav_item["title"] == "Projects" and not settings.PROJECTS_ENABLED: continue - if item["title"] == "Submissions" and settings.APPLY_NAV_SUBMISSIONS_ITEMS: + if nav_item["title"] == "Submissions" and settings.APPLY_NAV_SUBMISSIONS_ITEMS: nav_item["sub_items"] = settings.APPLY_NAV_SUBMISSIONS_ITEMS - if not _check_permission(user, nav_item["permission_method"]): + if not _check_permission(request.user, nav_item["permission_method"]): continue + + nav_item["is_active"] = _calculate_is_active( + nav_item["url"], nav_item.get("active_url_regex"), request_path + ) + if sub_items := nav_item.get("sub_items"): - nav_item["sub_items"] = list( - filter( - lambda x: _check_permission(user, x["permission_method"]), - sub_items, - ) - ) + filtered_sub_items = [] + any_sub_item_active = False + + for sub_item_original in sub_items: + sub_item = sub_item_original.copy() # Ensure we work with a copy + if _check_permission(request.user, sub_item["permission_method"]): + sub_item["is_active"] = _calculate_is_active( + sub_item["url"], sub_item.get("active_url_regex"), request_path + ) + if sub_item["is_active"]: + any_sub_item_active = True + filtered_sub_items.append(sub_item) + + nav_item["sub_items"] = filtered_sub_items + + # If any sub-item is active, mark the main item as active + # This ensures parent tab is highlighted if a child is active, + # even if the parent's own URL/regex didn't match. + if any_sub_item_active: + nav_item["is_active"] = True + nav_items.append(nav_item) return nav_items diff --git a/hypha/core/tables.py b/hypha/core/tables.py new file mode 100644 index 0000000000..899e81ef2a --- /dev/null +++ b/hypha/core/tables.py @@ -0,0 +1,21 @@ +import django_tables2 as tables +from django.conf import settings +from django.utils.html import format_html + + +class RelativeTimeColumn(tables.DateTimeColumn): + def __init__(self, date_format=None, prefix="", **kwargs): + self.date_format = date_format or settings.SHORT_DATETIME_FORMAT + self.prefix = prefix + super().__init__(**kwargs) + + def render(self, value): + if not value: + return "—" + + return format_html( + "{}", + value.isoformat(), + self.prefix, + value.strftime(self.date_format), + ) diff --git a/hypha/core/templates/components/admin_bar.html b/hypha/core/templates/components/admin_bar.html deleted file mode 100644 index ebd9378c94..0000000000 --- a/hypha/core/templates/components/admin_bar.html +++ /dev/null @@ -1,13 +0,0 @@ -{% load components i18n %} - -
    -
    -
    - {% render_slot slots.back_link %} -

    {% render_slot slots.header %}

    - {% if slots.sub_heading %}

    {% render_slot slots.sub_heading %}

    {% endif %} -
    - {% if slots.buttons %}
    {% render_slot slots.buttons %}
    {% endif %} - {% render_slot slots.inner_block %} -
    -
    diff --git a/hypha/core/templates/components/dropdown-menu.html b/hypha/core/templates/components/dropdown-menu.html index c1d327741d..2dfda43eac 100644 --- a/hypha/core/templates/components/dropdown-menu.html +++ b/hypha/core/templates/components/dropdown-menu.html @@ -22,7 +22,7 @@ > -

    {{ answers.question }}
    inside a
    for improved styling and layout, + * unless the table is already wrapped in such a container. + * + * The function runs on DOMContentLoaded and after htmx content updates (if htmx is present). + */ +(function () { + function proseCleanupAndTableWrap() { + // Select all containers with class "prose" that do not also have "not-prose" + const proseContainers = document.querySelectorAll(".prose:not(.not-prose)"); + proseContainers.forEach((container) => { + // Use a static NodeList to avoid issues when removing elements during iteration. + const paras = Array.from(container.querySelectorAll("p")); + for (const para of paras) { + // Remove

    tags with only whitespace or invisible characters inside. + if ( + !para.textContent || + para.textContent.replace(/\u200B/g, "").trim() === "" + ) { + para.remove(); + continue; + } + // Set dir="auto" so browsers set the correct directionality (ltr/rtl). + if (para.getAttribute("dir") !== "auto") { + para.setAttribute("dir", "auto"); + } + } + + // Select all

    elements inside the container that are not already wrapped. + const tables = container.querySelectorAll("table"); + tables.forEach((table) => { + // Check if the table is already wrapped to avoid double-wrapping + if (!table.parentElement.classList.contains("table-container")) { + const table_wrapper = document.createElement("div"); + table_wrapper.classList.add("table-container"); + table.parentNode.insertBefore(table_wrapper, table); + table_wrapper.appendChild(table); + } + }); + }); + } + + // Run on DOMContentLoaded + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", proseCleanupAndTableWrap); + } else { + proseCleanupAndTableWrap(); + } + + // Also run on htmx:afterSettle if htmx is present + if (window.htmx) { + window.htmx.on("htmx:afterSettle", proseCleanupAndTableWrap); + } +})(); diff --git a/hypha/static_src/javascript/behaviours/theme-toggle.js b/hypha/static_src/javascript/behaviours/theme-toggle.js new file mode 100644 index 0000000000..adb05d1c8a --- /dev/null +++ b/hypha/static_src/javascript/behaviours/theme-toggle.js @@ -0,0 +1,62 @@ +let prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; + +function setTheme(mode) { + if (mode !== "light" && mode !== "dark" && mode !== "auto") { + console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`); + mode = "auto"; + } + document.documentElement.dataset.theme = mode; + localStorage.setItem("theme", mode); +} + +function cycleTheme() { + const currentTheme = localStorage.getItem("theme") || "auto"; + + if (prefersDark) { + // Auto (dark) -> Light -> Dark + if (currentTheme === "auto") { + setTheme("light"); + } else if (currentTheme === "light") { + setTheme("dark"); + } else { + setTheme("auto"); + } + } else { + // Auto (light) -> Dark -> Light + if (currentTheme === "auto") { + setTheme("dark"); + } else if (currentTheme === "dark") { + setTheme("light"); + } else { + setTheme("auto"); + } + } +} + +function initTheme() { + // set theme defined in localStorage if there is one, or fallback to auto mode + const currentTheme = localStorage.getItem("theme"); + currentTheme ? setTheme(currentTheme) : setTheme("auto"); +} + +function setupTheme() { + // Attach event handlers for toggling themes + let buttons = document.getElementsByClassName("theme-toggle"); + for (var i = 0; i < buttons.length; i++) { + buttons[i].addEventListener("click", cycleTheme); + } +} + +initTheme(); + +document.addEventListener("DOMContentLoaded", function () { + setupTheme(); +}); + +// reset theme and release image if auto mode activated and os preferences have changed +window + .matchMedia("(prefers-color-scheme: dark)") + .addEventListener("change", function (e) { + prefersDark = e.matches; + initTheme(); + }); diff --git a/hypha/static_src/javascript/file-uploads.js b/hypha/static_src/javascript/file-uploads.js index c2efe9119f..bde64e6bad 100644 --- a/hypha/static_src/javascript/file-uploads.js +++ b/hypha/static_src/javascript/file-uploads.js @@ -1,7 +1,13 @@ // We use htmx.onLoad() so it will initialise file uploads in htmx dialogs. htmx.onLoad(function () { + // Extract DOM element references + const forms = document.querySelectorAll("form"); + const fileGroups = document.querySelectorAll("[data-js-file-upload]"); + const hiddenInputs = document.querySelectorAll("input[type=hidden]"); + const fileInputs = document.querySelectorAll("input[type='file'][required]"); + // Initialize django-file-form - document.querySelectorAll("form").forEach(function (form) { + forms.forEach(function (form) { // Prevent initializing it multiple times and run it for forms // that have a `form_id` field added by django-file-form. if (!form.initUploadFieldsDone && form.querySelector("[name=form_id]")) { @@ -15,11 +21,11 @@ htmx.onLoad(function () { * @param {object} form The form to initialize. */ function init(form) { - if (document.querySelectorAll(".form__group--file").length) { + if (fileGroups.length) { window.initUploadFields(form); // Hide wrapper elements for hidden inputs added by django-file-form - document.querySelectorAll("input[type=hidden]").forEach(function (input) { + hiddenInputs.forEach(function (input) { const closestFormGroup = input.closest(".form__group"); if (closestFormGroup) { closestFormGroup.style.display = "none"; @@ -29,8 +35,6 @@ htmx.onLoad(function () { } // Handle client side validation for required file fields - let fileInputs = document.querySelectorAll("input[type='file'][required]"); - fileInputs.forEach((input) => { input.addEventListener("invalid", function (event) { event.preventDefault(); // Prevent default browser behavior diff --git a/hypha/static_src/javascript/multi-input-fields-alpine.js b/hypha/static_src/javascript/multi-input-fields-alpine.js new file mode 100644 index 0000000000..0758a1070d --- /dev/null +++ b/hypha/static_src/javascript/multi-input-fields-alpine.js @@ -0,0 +1,86 @@ +document.addEventListener("alpine:init", () => { + Alpine.store("multiInput", { + fields: {}, + + initField(fieldId, maxIndex) { + if (!this.fields[fieldId]) { + this.fields[fieldId] = { + visibleCount: 1, + maxIndex: + maxIndex !== null ? maxIndex : this.getMaxIndexFromDOM(fieldId), + initialized: false, + }; + } + + // Update maxIndex if provided (in case a field with button initializes after others) + if (maxIndex !== null && this.fields[fieldId].maxIndex < maxIndex) { + this.fields[fieldId].maxIndex = maxIndex; + } + + if (!this.fields[fieldId].initialized) { + this.initializeVisibility(fieldId); + this.fields[fieldId].initialized = true; + } + }, + + getMaxIndexFromDOM(fieldId) { + let maxIndex = 0; + let element = document.getElementById(`id_${fieldId}_${maxIndex}`); + while (element) { + maxIndex++; + element = document.getElementById(`id_${fieldId}_${maxIndex}`); + } + return Math.max(0, maxIndex - 1); + }, + + initializeVisibility(fieldId) { + const field = this.fields[fieldId]; + if (!field) return; + + let filledCount = 0; + for (let i = 0; i <= field.maxIndex; i++) { + const fieldElement = document.getElementById(`id_${fieldId}_${i}`); + if (fieldElement && fieldElement.value.trim() !== "") { + filledCount++; + } + } + field.visibleCount = Math.max(1, filledCount); + }, + + isVisible(fieldId, index) { + const field = this.fields[fieldId]; + return field ? index < field.visibleCount : index === 0; + }, + + showNext(fieldId) { + const field = this.fields[fieldId]; + if (field && field.visibleCount <= field.maxIndex) { + field.visibleCount++; + } + }, + + canAddMore(fieldId) { + const field = this.fields[fieldId]; + return field ? field.visibleCount <= field.maxIndex : false; + }, + }); +}); + +function multiInputField(fieldId, fieldName, maxIndex) { + return { + fieldId: fieldId, + fieldIndex: parseInt(fieldName.split("_").pop()), + maxIndex: maxIndex, + + initField() { + Alpine.store("multiInput").initField(this.fieldId, this.maxIndex); + }, + + isVisible() { + return Alpine.store("multiInput").isVisible( + this.fieldId, + this.fieldIndex + ); + }, + }; +} diff --git a/hypha/static_src/javascript/multi-input-fields.js b/hypha/static_src/javascript/multi-input-fields.js deleted file mode 100644 index cd806bb7c1..0000000000 --- a/hypha/static_src/javascript/multi-input-fields.js +++ /dev/null @@ -1,42 +0,0 @@ -(function ($) { - // Visibility Index is set to 0 initially in the backend. But in case of edit application forms - // with multiple values already set, we need to update it. The visibility index helps - // to get the next field from the list of hidden inputs to be shown to an applicant on clicking the add button. - // For example, a total of 5 multiple inputs, 3 values are already set by applicant while creating a submission. - // On edit form, the visibility index should be updates so when the user clicks add, the 4th input should be displayed. - $(".multi-input-add-btn").each(function () { - var multiFieldId = $(this).data("multi-field-id"); - const multiMaxIndex = $(this).data("multi-max-index"); - var multiFieldInputs = $( - ".form__item[data-multi-field-for='" + multiFieldId + "']" - ); - var multiFieldHiddenInput = $( - ".form__item.multi-input-field-hidden[data-multi-field-for='" + - multiFieldId + - "']" - ); - var multiVisibilityIndex = multiFieldInputs.index(multiFieldHiddenInput); - if (multiVisibilityIndex >= 0) { - $(this).data("multi-visibility-index", multiVisibilityIndex); - } else if (multiVisibilityIndex === -1) { - $(this).data("multi-visibility-index", multiMaxIndex); - } - }); - - $(".multi-input-add-btn").click(function () { - var multiFieldId = $(this).data("multi-field-id"); - var multiVisibilityIndex = $(this).data("multi-visibility-index"); - const multiMaxIndex = $(this).data("multi-max-index"); - - var multiShowIndex = multiVisibilityIndex + 1; - if (multiShowIndex <= multiMaxIndex) { - var multiShowId = "id_" + multiFieldId + "_" + multiShowIndex; - $("#" + multiShowId) - .parent(".form__item") - .removeClass("multi-input-field-hidden"); - $(this).data("multi-visibility-index", multiShowIndex); - } else { - $(this).hide(); - } - }); -})(jQuery); diff --git a/hypha/static_src/javascript/past-reports-pagination.js b/hypha/static_src/javascript/past-reports-pagination.js deleted file mode 100644 index a6ac672b39..0000000000 --- a/hypha/static_src/javascript/past-reports-pagination.js +++ /dev/null @@ -1,32 +0,0 @@ -(function ($) { - /** - * This script is used to paginate the past reports table. - */ - function pastReportsPagination() { - $(".js-data-block-pagination").click((e) => { - e.preventDefault(); - showNextTen(); - }); - } - - /** - * Show next ten. - */ - function showNextTen() { - const [...nextTen] = $(".js-past-reports-table tr.hidden").slice(0, 10); - nextTen.forEach((item) => item.classList.remove("hidden")); - checkRemaining(); - } - - /** - * Check remaining. - */ - function checkRemaining() { - const [...remaining] = $(".js-past-reports-table tr.hidden"); - if (remaining.length === 0) { - $(".js-data-block-pagination").addClass("hidden"); - } - } - - pastReportsPagination(); -})(jQuery); diff --git a/hypha/static_src/javascript/report-calculator.js b/hypha/static_src/javascript/report-calculator.js index 23bcdb8a07..7458a18767 100644 --- a/hypha/static_src/javascript/report-calculator.js +++ b/hypha/static_src/javascript/report-calculator.js @@ -54,15 +54,15 @@ document.addEventListener("htmx:afterRequest", function () { } function showHideFrequencyInputs() { const elements = document.querySelectorAll( - ".form__group--report-every, .form__group--schedule" + ".form__group--report-every, .form__group--schedule, [data-js-report-frequency-card]" ); if (doesNotRepeatInput.checked) { elements.forEach((element) => { - element.classList.add("!hidden"); + element.style.display = "none"; }); } else { elements.forEach((element) => { - element.classList.remove("!hidden"); + element.style.display = "flex"; }); } } diff --git a/hypha/static_src/javascript/submission-form-copy.js b/hypha/static_src/javascript/submission-form-copy.js index df022def0e..e8a1412b63 100644 --- a/hypha/static_src/javascript/submission-form-copy.js +++ b/hypha/static_src/javascript/submission-form-copy.js @@ -85,9 +85,7 @@ ) { var $button = $(" diff --git a/hypha/templates/includes/dialog_form_base.html b/hypha/templates/includes/dialog_form_base.html index db232832a4..377c29c77c 100644 --- a/hypha/templates/includes/dialog_form_base.html +++ b/hypha/templates/includes/dialog_form_base.html @@ -14,7 +14,7 @@ {{ hidden }} {% endfor %} -
    +
    {% for field in form.visible_fields %} {% if field.field %} {% include "forms/includes/field.html" %} @@ -22,19 +22,19 @@ {{ field }} {% endif %} {% endfor %} -
    + -
    +
    {% trans "Delete" as delete %}
    diff --git a/hypha/templates/includes/header-logo.html b/hypha/templates/includes/header-logo.html index bf0f46ccbf..9d8fc2e002 100644 --- a/hypha/templates/includes/header-logo.html +++ b/hypha/templates/includes/header-logo.html @@ -2,14 +2,14 @@ {% if settings.core.SystemSettings.site_logo_default %} {% image settings.core.SystemSettings.site_logo_default width-215 as logo_default %} - + {% if settings.core.SystemSettings.site_logo_mobile %} {% image settings.core.SystemSettings.site_logo_mobile width-60 as logo_mobile %} - + {% else %} - + {% endif %} {% else %} - - + + {% endif %} diff --git a/hypha/templates/includes/hijack-bar.html b/hypha/templates/includes/hijack-bar.html index 3ada581b71..f0c3a689b5 100644 --- a/hypha/templates/includes/hijack-bar.html +++ b/hypha/templates/includes/hijack-bar.html @@ -1,29 +1,28 @@ {% load i18n heroicons %} - {% csrf_token %} - - +
    {% heroicon_micro "exclamation-triangle" size=18 class="inline align-text-bottom" aria_hidden=true %} - {% blocktrans trimmed with user=request.user %} - You are currently working on behalf of {{ user }} - {% endblocktrans %} - <{{ request.user.email }}> - {% for role in request.user.get_role_names %} - - {{ role }} - - {% endfor %} - - - + + {% blocktrans trimmed with user=request.user %} + You are currently working on behalf of {{ user }} + {% endblocktrans %} + <{{ request.user.email }}> + {% for role in request.user.get_role_names %} + {{ role }} + {% endfor %} + - + +
    diff --git a/hypha/templates/includes/language-switcher.html b/hypha/templates/includes/language-switcher.html index 959df2896f..c4dc1d69ca 100644 --- a/hypha/templates/includes/language-switcher.html +++ b/hypha/templates/includes/language-switcher.html @@ -1,4 +1,6 @@ {% load i18n heroicons %} +{% get_language_info for LANGUAGE_CODE as current_lang %} +
    @@ -20,33 +26,46 @@ x-show="open" x-trap="open" x-transition - x-transition.origin.top + x-transition.origin.bottom role="dialog" aria-labelledby="dialogtitle" @click.outside="open = false" - class="overflow-y-auto absolute right-0 z-30 bg-white rounded-sm border shadow-md" + class="overflow-y-auto absolute right-0 bottom-full z-30 border shadow-md rounded-box bg-base-200" + id="id-language-switcher" > - -
    - {% get_available_languages as LANGUAGES %} - {% get_language_info_list for LANGUAGES as languages %} - {% if languages|length > 1 %} -
    - {% csrf_token %} - -
    - {% for language in languages %} -
    - - -
    - {% endfor %} - -
    - - {% else %} - {% trans "Can't switch language, only one language is active." %} - {% endif %} -
    + {% get_available_languages as LANGUAGES %} + {% get_language_info_list for LANGUAGES as languages %} + {% if languages|length > 1 %} +
    + {% csrf_token %} + + + + {% else %} +
    + {% heroicon_outline "information-circle" class="opacity-80 size-5" %} + {% trans "Can't switch language, only one language is active." %} +
    + {% endif %}
    diff --git a/hypha/templates/includes/menu-notifications.html b/hypha/templates/includes/menu-notifications.html index 6393c2c4d3..327506377a 100644 --- a/hypha/templates/includes/menu-notifications.html +++ b/hypha/templates/includes/menu-notifications.html @@ -6,22 +6,22 @@ x-on:keydown.escape="open = false" x-init="$watch('open', value => { if (value) { document.getElementById('id-task-list').dispatchEvent(new Event('htmx:fetch')); } })" > -
    -
    +
    {% trans "Your Tasks" %} @@ -46,14 +46,14 @@ hx-swap="innerHTML" hx-trigger="htmx:fetch, taskListUpdated from:body" > -
    -
    +
    +

    -
    -
    +
    +

    -
    -
    +
    +
    diff --git a/hypha/templates/includes/org_login_button.html b/hypha/templates/includes/org_login_button.html index ba2afddc12..4de5f6bd0f 100644 --- a/hypha/templates/includes/org_login_button.html +++ b/hypha/templates/includes/org_login_button.html @@ -1,8 +1,8 @@ {% load i18n heroicons %} diff --git a/hypha/templates/includes/pagination.html b/hypha/templates/includes/pagination.html deleted file mode 100644 index d650375f64..0000000000 --- a/hypha/templates/includes/pagination.html +++ /dev/null @@ -1,17 +0,0 @@ -{% load i18n %} -{% if paginator_page.paginator.num_pages > 1 %} - {% endif %} diff --git a/hypha/templates/includes/password_login_button.html b/hypha/templates/includes/password_login_button.html index d7dc1a705a..d5b0f99ccc 100644 --- a/hypha/templates/includes/password_login_button.html +++ b/hypha/templates/includes/password_login_button.html @@ -1,8 +1,8 @@ {% load i18n heroicons %} diff --git a/hypha/templates/includes/passwordless_login_button.html b/hypha/templates/includes/passwordless_login_button.html index d5e761326c..2605b62a22 100644 --- a/hypha/templates/includes/passwordless_login_button.html +++ b/hypha/templates/includes/passwordless_login_button.html @@ -1,8 +1,8 @@ {% load i18n heroicons %} diff --git a/hypha/templates/includes/user_menu.html b/hypha/templates/includes/user_menu.html index e259f093bc..d29100e680 100644 --- a/hypha/templates/includes/user_menu.html +++ b/hypha/templates/includes/user_menu.html @@ -4,11 +4,11 @@
    @@ -20,52 +20,52 @@ x-transition x-transition.origin.top @click.outside="show = false" - class="block absolute top-10 bg-white shadow-xl rounded-xs min-w-48 z-100000 border-y end-0" + class="block absolute top-10 shadow-xl bg-base-100 rounded-xs min-w-48 z-100000 border-y end-0" > - {% heroicon_outline "user" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-dark-blue" aria_hidden=true %} + {% heroicon_outline "user" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-primary" aria_hidden=true %} {% trans 'My account' %} {% if request.user.is_apply_staff %} - {% heroicon_outline "bolt" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-dark-blue" aria_hidden=true %} + {% heroicon_outline "bolt" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-primary" aria_hidden=true %} {% trans "Activity feed" %} - {% heroicon_outline "flag" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-dark-blue" aria_hidden=true %} + {% heroicon_outline "flag" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-primary" aria_hidden=true %} {% trans "My flagged" %} {% if perms.wagtailadmin.access_admin %} - {% heroicon_outline "cog-6-tooth" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-dark-blue" aria_hidden=true %} + {% heroicon_outline "cog-6-tooth" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-primary" aria_hidden=true %} {% trans "Administration" %} {% endif %} {% endif %} {% if HIJACK_ENABLE and not user.is_hijacked and user.is_superuser %} - {% heroicon_outline "arrows-right-left" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-dark-blue" aria_hidden=true %} + {% heroicon_outline "arrows-right-left" size=18 class="inline transition-transform group-hover:scale-110 group-hover:stroke-2 stroke-gray-500 group-hover:stroke-primary" aria_hidden=true %} {% trans "Switch User" %} {% endif %} @@ -76,10 +76,11 @@ {% csrf_token %} - @@ -88,7 +89,7 @@ {% trans "Log out" %} @@ -96,10 +97,10 @@
    {% else %} - {% heroicon_micro "user" class="inline w-4 h-4 align-text-bottom me-1" aria_hidden=true %} + {% heroicon_micro "user" class="inline align-text-bottom size-4 me-1" aria_hidden=true %} {% trans "Log in" %} {% if ENABLE_PUBLIC_SIGNUP %} {% trans " or Sign up" %} {% endif %} {% endif %} diff --git a/package-lock.json b/package-lock.json index e63bcc97aa..3bc3ddb060 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,11 +14,11 @@ "@babel/core": "^7.25.9", "@babel/preset-env": "^7.25.9", "@biomejs/biome": "^1.9.4", - "@tailwindcss/cli": "^4.0.13", - "@tailwindcss/forms": "^0.5.9", - "@tailwindcss/typography": "^0.5.15", + "@tailwindcss/cli": "^4.1.7", + "@tailwindcss/typography": "^0.5.16", "alpinejs": "^3.14.6", "core-js": "^3.39.0", + "daisyui": "^5.0.43", "daterangepicker": "^3.1.0", "htmx.org": "^2.0.3", "nodemon": "^3.1.7", @@ -1826,6 +1826,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", @@ -2245,78 +2258,73 @@ } }, "node_modules/@tailwindcss/cli": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.4.tgz", - "integrity": "sha512-gP05Qihh+cZ2FqD5fa0WJXx3KEk2YWUYv/RBKAyiOg0V4vYVDr/xlLc0sacpnVEXM45BVUR9U2hsESufYs6YTA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.7.tgz", + "integrity": "sha512-hJNjpov/UiJc9ZWH4j/eEQxqklADrD/71s+t8Y0wbyQVAwtLkSp+MeC/sHTb03X+28rfbe0fRXkiBsf73/IwPg==", "dev": true, "license": "MIT", "dependencies": { "@parcel/watcher": "^2.5.1", - "@tailwindcss/node": "4.1.4", - "@tailwindcss/oxide": "4.1.4", + "@tailwindcss/node": "4.1.7", + "@tailwindcss/oxide": "4.1.7", "enhanced-resolve": "^5.18.1", "mri": "^1.2.0", "picocolors": "^1.1.1", - "tailwindcss": "4.1.4" + "tailwindcss": "4.1.7" }, "bin": { "tailwindcss": "dist/index.mjs" } }, - "node_modules/@tailwindcss/forms": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz", - "integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mini-svg-data-uri": "^1.2.3" - }, - "peerDependencies": { - "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1" - } - }, "node_modules/@tailwindcss/node": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.4.tgz", - "integrity": "sha512-MT5118zaiO6x6hNA04OWInuAiP1YISXql8Z+/Y8iisV5nuhM8VXlyhRuqc2PEviPszcXI66W44bCIk500Oolhw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.7.tgz", + "integrity": "sha512-9rsOpdY9idRI2NH6CL4wORFY0+Q6fnx9XP9Ju+iq/0wJwGD5IByIgFmwVbyy4ymuyprj8Qh4ErxMKTUL4uNh3g==", "dev": true, "license": "MIT", "dependencies": { + "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", - "lightningcss": "1.29.2", - "tailwindcss": "4.1.4" + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.7" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.4.tgz", - "integrity": "sha512-p5wOpXyOJx7mKh5MXh5oKk+kqcz8T+bA3z/5VWWeQwFrmuBItGwz8Y2CHk/sJ+dNb9B0nYFfn0rj/cKHZyjahQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.7.tgz", + "integrity": "sha512-5SF95Ctm9DFiUyjUPnDGkoKItPX/k+xifcQhcqX5RA85m50jw1pT/KzjdvlqxRja45Y52nR4MR9fD1JYd7f8NQ==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, "engines": { "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.4", - "@tailwindcss/oxide-darwin-arm64": "4.1.4", - "@tailwindcss/oxide-darwin-x64": "4.1.4", - "@tailwindcss/oxide-freebsd-x64": "4.1.4", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.4", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.4", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.4", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.4", - "@tailwindcss/oxide-linux-x64-musl": "4.1.4", - "@tailwindcss/oxide-wasm32-wasi": "4.1.4", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.4", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.4" + "@tailwindcss/oxide-android-arm64": "4.1.7", + "@tailwindcss/oxide-darwin-arm64": "4.1.7", + "@tailwindcss/oxide-darwin-x64": "4.1.7", + "@tailwindcss/oxide-freebsd-x64": "4.1.7", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.7", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.7", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.7", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.7", + "@tailwindcss/oxide-linux-x64-musl": "4.1.7", + "@tailwindcss/oxide-wasm32-wasi": "4.1.7", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.7", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.7" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.4.tgz", - "integrity": "sha512-xMMAe/SaCN/vHfQYui3fqaBDEXMu22BVwQ33veLc8ep+DNy7CWN52L+TTG9y1K397w9nkzv+Mw+mZWISiqhmlA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.7.tgz", + "integrity": "sha512-IWA410JZ8fF7kACus6BrUwY2Z1t1hm0+ZWNEzykKmMNM09wQooOcN/VXr0p/WJdtHZ90PvJf2AIBS/Ceqx1emg==", "cpu": [ "arm64" ], @@ -2331,9 +2339,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.4.tgz", - "integrity": "sha512-JGRj0SYFuDuAGilWFBlshcexev2hOKfNkoX+0QTksKYq2zgF9VY/vVMq9m8IObYnLna0Xlg+ytCi2FN2rOL0Sg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.7.tgz", + "integrity": "sha512-81jUw9To7fimGGkuJ2W5h3/oGonTOZKZ8C2ghm/TTxbwvfSiFSDPd6/A/KE2N7Jp4mv3Ps9OFqg2fEKgZFfsvg==", "cpu": [ "arm64" ], @@ -2348,9 +2356,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.4.tgz", - "integrity": "sha512-sdDeLNvs3cYeWsEJ4H1DvjOzaGios4QbBTNLVLVs0XQ0V95bffT3+scptzYGPMjm7xv4+qMhCDrkHwhnUySEzA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.7.tgz", + "integrity": "sha512-q77rWjEyGHV4PdDBtrzO0tgBBPlQWKY7wZK0cUok/HaGgbNKecegNxCGikuPJn5wFAlIywC3v+WMBt0PEBtwGw==", "cpu": [ "x64" ], @@ -2365,9 +2373,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.4.tgz", - "integrity": "sha512-VHxAqxqdghM83HslPhRsNhHo91McsxRJaEnShJOMu8mHmEj9Ig7ToHJtDukkuLWLzLboh2XSjq/0zO6wgvykNA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.7.tgz", + "integrity": "sha512-RfmdbbK6G6ptgF4qqbzoxmH+PKfP4KSVs7SRlTwcbRgBwezJkAO3Qta/7gDy10Q2DcUVkKxFLXUQO6J3CRvBGw==", "cpu": [ "x64" ], @@ -2382,9 +2390,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.4.tgz", - "integrity": "sha512-OTU/m/eV4gQKxy9r5acuesqaymyeSCnsx1cFto/I1WhPmi5HDxX1nkzb8KYBiwkHIGg7CTfo/AcGzoXAJBxLfg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.7.tgz", + "integrity": "sha512-OZqsGvpwOa13lVd1z6JVwQXadEobmesxQ4AxhrwRiPuE04quvZHWn/LnihMg7/XkN+dTioXp/VMu/p6A5eZP3g==", "cpu": [ "arm" ], @@ -2399,9 +2407,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.4.tgz", - "integrity": "sha512-hKlLNvbmUC6z5g/J4H+Zx7f7w15whSVImokLPmP6ff1QqTVE+TxUM9PGuNsjHvkvlHUtGTdDnOvGNSEUiXI1Ww==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.7.tgz", + "integrity": "sha512-voMvBTnJSfKecJxGkoeAyW/2XRToLZ227LxswLAwKY7YslG/Xkw9/tJNH+3IVh5bdYzYE7DfiaPbRkSHFxY1xA==", "cpu": [ "arm64" ], @@ -2416,9 +2424,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.4.tgz", - "integrity": "sha512-X3As2xhtgPTY/m5edUtddmZ8rCruvBvtxYLMw9OsZdH01L2gS2icsHRwxdU0dMItNfVmrBezueXZCHxVeeb7Aw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.7.tgz", + "integrity": "sha512-PjGuNNmJeKHnP58M7XyjJyla8LPo+RmwHQpBI+W/OxqrwojyuCQ+GUtygu7jUqTEexejZHr/z3nBc/gTiXBj4A==", "cpu": [ "arm64" ], @@ -2433,9 +2441,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.4.tgz", - "integrity": "sha512-2VG4DqhGaDSmYIu6C4ua2vSLXnJsb/C9liej7TuSO04NK+JJJgJucDUgmX6sn7Gw3Cs5ZJ9ZLrnI0QRDOjLfNQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.7.tgz", + "integrity": "sha512-HMs+Va+ZR3gC3mLZE00gXxtBo3JoSQxtu9lobbZd+DmfkIxR54NO7Z+UQNPsa0P/ITn1TevtFxXTpsRU7qEvWg==", "cpu": [ "x64" ], @@ -2450,9 +2458,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.4.tgz", - "integrity": "sha512-v+mxVgH2kmur/X5Mdrz9m7TsoVjbdYQT0b4Z+dr+I4RvreCNXyCFELZL/DO0M1RsidZTrm6O1eMnV6zlgEzTMQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.7.tgz", + "integrity": "sha512-MHZ6jyNlutdHH8rd+YTdr3QbXrHXqwIhHw9e7yXEBcQdluGwhpQY2Eku8UZK6ReLaWtQ4gijIv5QoM5eE+qlsA==", "cpu": [ "x64" ], @@ -2467,9 +2475,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.4.tgz", - "integrity": "sha512-2TLe9ir+9esCf6Wm+lLWTMbgklIjiF0pbmDnwmhR9MksVOq+e8aP3TSsXySnBDDvTTVd/vKu1aNttEGj3P6l8Q==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.7.tgz", + "integrity": "sha512-ANaSKt74ZRzE2TvJmUcbFQ8zS201cIPxUDm5qez5rLEwWkie2SkGtA4P+GPTj+u8N6JbPrC8MtY8RmJA35Oo+A==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -2485,10 +2493,10 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.0", - "@emnapi/runtime": "^1.4.0", - "@emnapi/wasi-threads": "^1.0.1", - "@napi-rs/wasm-runtime": "^0.2.8", + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.9", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, @@ -2497,9 +2505,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.4.tgz", - "integrity": "sha512-VlnhfilPlO0ltxW9/BgfLI5547PYzqBMPIzRrk4W7uupgCt8z6Trw/tAj6QUtF2om+1MH281Pg+HHUJoLesmng==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.7.tgz", + "integrity": "sha512-HUiSiXQ9gLJBAPCMVRk2RT1ZrBjto7WvqsPBwUrNK2BcdSxMnk19h4pjZjI7zgPhDxlAbJSumTC4ljeA9y0tEw==", "cpu": [ "arm64" ], @@ -2514,9 +2522,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.4.tgz", - "integrity": "sha512-+7S63t5zhYjslUGb8NcgLpFXD+Kq1F/zt5Xv5qTv7HaFTG/DHyHD9GA6ieNAxhgyA4IcKa/zy7Xx4Oad2/wuhw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.7.tgz", + "integrity": "sha512-rYHGmvoHiLJ8hWucSfSOEmdCBIGZIq7SpkPRSqLsH2Ab2YUNgKeAPT1Fi2cx3+hnYOrAb0jp9cRyode3bBW4mQ==", "cpu": [ "x64" ], @@ -2530,6 +2538,16 @@ "node": ">= 10" } }, + "node_modules/@tailwindcss/oxide/node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/@tailwindcss/typography": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz", @@ -2886,6 +2904,16 @@ "fsevents": "~2.3.2" } }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3065,6 +3093,16 @@ "node": ">=4" } }, + "node_modules/daisyui": { + "version": "5.0.43", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.0.43.tgz", + "integrity": "sha512-2pshHJ73vetSpsbAyaOncGnNYL0mwvgseS1EWy1I9Qpw8D11OuBoDNIWrPIME4UFcq2xuff3A9x+eXbuFR9fUQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/saadeghi/daisyui?sponsor=1" + } + }, "node_modules/daterangepicker": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/daterangepicker/-/daterangepicker-3.1.0.tgz", @@ -3863,9 +3901,9 @@ "license": "MIT" }, "node_modules/lightningcss": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", - "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -3879,22 +3917,22 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-darwin-arm64": "1.29.2", - "lightningcss-darwin-x64": "1.29.2", - "lightningcss-freebsd-x64": "1.29.2", - "lightningcss-linux-arm-gnueabihf": "1.29.2", - "lightningcss-linux-arm64-gnu": "1.29.2", - "lightningcss-linux-arm64-musl": "1.29.2", - "lightningcss-linux-x64-gnu": "1.29.2", - "lightningcss-linux-x64-musl": "1.29.2", - "lightningcss-win32-arm64-msvc": "1.29.2", - "lightningcss-win32-x64-msvc": "1.29.2" + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", - "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", "cpu": [ "arm64" ], @@ -3913,9 +3951,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", - "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", "cpu": [ "x64" ], @@ -3934,9 +3972,9 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", - "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", "cpu": [ "x64" ], @@ -3955,9 +3993,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", - "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", "cpu": [ "arm" ], @@ -3976,9 +4014,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", - "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", "cpu": [ "arm64" ], @@ -3997,9 +4035,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", - "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", "cpu": [ "arm64" ], @@ -4018,9 +4056,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", - "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", "cpu": [ "x64" ], @@ -4039,9 +4077,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", - "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", "cpu": [ "x64" ], @@ -4060,9 +4098,9 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", - "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", "cpu": [ "arm64" ], @@ -4081,9 +4119,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", - "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", "cpu": [ "x64" ], @@ -4102,9 +4140,9 @@ } }, "node_modules/lightningcss/node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -4163,6 +4201,16 @@ "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, "node_modules/make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -4251,16 +4299,6 @@ "node": ">=8.6" } }, - "node_modules/mini-svg-data-uri": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", - "dev": true, - "license": "MIT", - "bin": { - "mini-svg-data-uri": "cli.js" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4274,6 +4312,45 @@ "node": "*" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -5477,9 +5554,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.4.tgz", - "integrity": "sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz", + "integrity": "sha512-kr1o/ErIdNhTz8uzAYL7TpaUuzKIE6QPQ4qmSdxnoX/lo+5wmUHQA6h3L5yIqEImSRnAAURDirLu/BgiXGPAhg==", "dev": true, "license": "MIT" }, @@ -5493,6 +5570,34 @@ "node": ">=6" } }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index 15a35a8bf2..da3a6455a1 100644 --- a/package.json +++ b/package.json @@ -26,10 +26,11 @@ "@babel/core": "^7.25.9", "@babel/preset-env": "^7.25.9", "@biomejs/biome": "^1.9.4", - "@tailwindcss/forms": "^0.5.9", - "@tailwindcss/typography": "^0.5.15", + "@tailwindcss/cli": "^4.1.7", + "@tailwindcss/typography": "^0.5.16", "alpinejs": "^3.14.6", "core-js": "^3.39.0", + "daisyui": "^5.0.43", "daterangepicker": "^3.1.0", "htmx.org": "^2.0.3", "nodemon": "^3.1.7", @@ -37,8 +38,7 @@ "sass": "^1.81.1", "stylelint": "^16.11.0", "stylelint-config-standard": "^36.0.1", - "stylelint-config-standard-scss": "^13.1.0", - "@tailwindcss/cli": "^4.0.13" + "stylelint-config-standard-scss": "^13.1.0" }, "scripts": { "heroku-postbuild": "npm run build", diff --git a/pyproject.toml b/pyproject.toml index f7427957ed..52b83363b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "hypha" -description = "A open source submission management platform to receive and manage applications for funding." +description = "A open source submission management platform to receive and manage applications for funding" readme = "README.md" version = "5.33.0" requires-python = ">=3.10" @@ -62,6 +62,8 @@ dependencies = [ "wagtail-modeladmin~=2.2.0", "redis~=6.2.0", "django-viewflow~=2.2.11", + "django-cotton~=2.1", + "html-diff>=0.4.1", ] [dependency-groups] diff --git a/requirements/dev.txt b/requirements/dev.txt index b570b31636..b864c6658b 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -4,9 +4,9 @@ amqp==5.3.1 \ --hash=sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2 \ --hash=sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432 # via kombu -anyascii==0.3.2 \ - --hash=sha256:3b3beef6fc43d9036d3b0529050b0c48bfad8bc960e9e562d7223cfb94fe45d4 \ - --hash=sha256:9d5d32ef844fe225b8bc7cba7f950534fae4da27a9bf3a6bea2cb0ea46ce4730 +anyascii==0.3.3 \ + --hash=sha256:c94e9dd9d47b3d9494eca305fef9447d00b4bf1a32aff85aa746fa3ec7fb95c3 \ + --hash=sha256:f5ab5e53c8781a36b5a40e1296a0eeda2f48c649ef10c3921c1381b1d00dee7a # via wagtail anyio==4.9.0 \ --hash=sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028 \ @@ -85,19 +85,20 @@ beautifulsoup4==4.11.2 \ --hash=sha256:0e79446b10b3ecb499c1556f7e228a53e64a2bfcebd455f370d8927cb5b59e39 \ --hash=sha256:bc4bdda6717de5a2987436fb8d72f45dc90dd856bdfd512a1314ce90349a0106 # via + # html-diff # htmldocx # wagtail billiard==4.2.1 \ --hash=sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f \ --hash=sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb # via celery -boto3==1.38.41 \ - --hash=sha256:6119e9f272b9f004f052ca78ce94d3fe10198bc159ae808f75c0e1b9c07518bd \ - --hash=sha256:c6710fc533c8e1f5d1f025c74ffe1222c3659094cd51c076ec50c201a54c8f22 +boto3==1.38.46 \ + --hash=sha256:9c8e88a32a6465e5905308708cff5b17547117f06982908bdfdb0108b4a65079 \ + --hash=sha256:d1ca2b53138afd0341e1962bd52be6071ab7a63c5b4f89228c5ef8942c40c852 # via hypha -botocore==1.38.41 \ - --hash=sha256:06069a06f1352accb1f6c9505d6e323753627112be80a9d2e057c6d9c9779ffd \ - --hash=sha256:98e3fed636ebb519320c4b2d078db6fa6099b052b4bb9b5c66632a5a7fe72507 +botocore==1.38.46 \ + --hash=sha256:8798e5a418c27cf93195b077153644aea44cb171fcd56edc1ecebaa1e49e226e \ + --hash=sha256:89ca782ffbf2e8769ca9c89234cfa5ca577f1987d07d913ee3c68c4776b1eb5b # via # boto3 # s3transfer @@ -246,9 +247,9 @@ click-didyoumean==0.3.1 \ --hash=sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463 \ --hash=sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c # via celery -click-plugins==1.1.1 \ - --hash=sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b \ - --hash=sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8 +click-plugins==1.1.1.2 \ + --hash=sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6 \ + --hash=sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261 # via celery click-repl==0.3.0 \ --hash=sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9 \ @@ -400,6 +401,7 @@ django==4.2.23 \ # django-anymail # django-basic-auth-ip-whitelist # django-browser-reload + # django-cotton # django-debug-toolbar # django-extensions # django-filter @@ -443,6 +445,10 @@ django-basic-auth-ip-whitelist==0.8.0 \ django-browser-reload==1.18.0 \ --hash=sha256:c5f0b134723cbf2a0dc9ae1ee1d38e42db28fe23c74cdee613ba3ef286d04735 \ --hash=sha256:ed4cc2fb83c3bf6c30b54107a1a6736c0b896e62e4eba666d81005b9f2ecf6f8 +django-cotton==2.1.2 \ + --hash=sha256:8492cb7cfe881455a1b9dfaaaec2d1943494a1d3d2e2066ac7da6ce31afceef3 \ + --hash=sha256:ad467f725239bf43004dad87dfc70f95c08d96efde4166d4bfb815e7cb72c56f + # via hypha django-countries==7.6.1 \ --hash=sha256:1ed20842fe0f6194f91faca21076649513846a8787c9eb5aeec3cbe1656b8acc \ --hash=sha256:c772d4e3e54afcc5f97a018544e96f246c6d9f1db51898ab0c15cd57e19437cf @@ -489,9 +495,9 @@ django-hijack==3.7.2 \ --hash=sha256:dc834a015082dd2d49afd13da6cf6f571ce1a16894d6070887261a37633f8d06 \ --hash=sha256:eb02d285ec1564bfa77ac2e73b9bca28848caa7b04c1e1eef3d573353eb9efaa # via hypha -django-htmx==1.23.1 \ - --hash=sha256:45febb80d2e85ee1da01dca61429d6f835ef176949cda4ecc5ae2e729d2ff53d \ - --hash=sha256:6a23ee1e74f54a28eca4ccb48191a585529fbad5cbd5b5c3d8ec1a16b8557090 +django-htmx==1.23.2 \ + --hash=sha256:65a8c8825fcae983b94aedce26af96a70717ab185d55cdb8a7a4bb68863ab079 \ + --hash=sha256:c288fe92bdcfa7c2ed9665d6d23cc55c6693a7cc8d22cf0a01e1e38318874030 # via hypha django-modelcluster==6.4 \ --hash=sha256:0102d00e6b884721ba21e32edb716548e0dead7880e130aa2e04854bd384a42f \ @@ -656,6 +662,10 @@ hjson==3.1.0 \ # via # mkdocs-macros-plugin # super-collections +html-diff==0.4.1 \ + --hash=sha256:4260ad08d80a043f34a45721d429d3462ec2738b9002c7e5bd75040bdcd40528 \ + --hash=sha256:b64d90514abecd13702b936ec4221aa103f4f0df96427bf8387bb18ca6c0ab74 + # via hypha html5lib==1.1 \ --hash=sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d \ --hash=sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f @@ -715,82 +725,70 @@ lark==1.2.2 \ --hash=sha256:c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c \ --hash=sha256:ca807d0162cd16cef15a8feecb862d7319e7a09bdb13aef927968e45040fed80 # via hypha -lxml==5.4.0 \ - --hash=sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5 \ - --hash=sha256:0a01ce7d8479dce84fc03324e3b0c9c90b1ece9a9bb6a1b6c9025e7e4520e78c \ - --hash=sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b \ - --hash=sha256:0cef4feae82709eed352cd7e97ae062ef6ae9c7b5dbe3663f104cd2c0e8d94ba \ - --hash=sha256:0ea0252b51d296a75f6118ed0d8696888e7403408ad42345d7dfd0d1e93309a7 \ - --hash=sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422 \ - --hash=sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8 \ - --hash=sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a \ - --hash=sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982 \ - --hash=sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8 \ - --hash=sha256:1b717b00a71b901b4667226bba282dd462c42ccf618ade12f9ba3674e1fabc55 \ - --hash=sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2 \ - --hash=sha256:20e16c08254b9b6466526bc1828d9370ee6c0d60a4b64836bc3ac2917d1e16df \ - --hash=sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551 \ - --hash=sha256:27a9ded0f0b52098ff89dd4c418325b987feed2ea5cc86e8860b0f844285d740 \ - --hash=sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60 \ - --hash=sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e \ - --hash=sha256:3a3178b4873df8ef9457a4875703488eb1622632a9cee6d76464b60e90adbfcd \ - --hash=sha256:3b9c2754cef6963f3408ab381ea55f47dabc6f78f4b8ebb0f0b25cf1ac1f7609 \ - --hash=sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20 \ - --hash=sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61 \ - --hash=sha256:4329422de653cdb2b72afa39b0aa04252fca9071550044904b2e7036d9d97fe4 \ - --hash=sha256:43d549b876ce64aa18b2328faff70f5877f8c6dede415f80a2f799d31644d776 \ - --hash=sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779 \ - --hash=sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c \ - --hash=sha256:4b7ce10634113651d6f383aa712a194179dcd496bd8c41e191cec2099fa09de5 \ - --hash=sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f \ - --hash=sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54 \ - --hash=sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e \ - --hash=sha256:53370c26500d22b45182f98847243efb518d268374a9570409d2e2276232fd37 \ - --hash=sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7 \ - --hash=sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7 \ - --hash=sha256:696ea9e87442467819ac22394ca36cb3d01848dad1be6fac3fb612d3bd5a12cf \ - --hash=sha256:6ef80aeac414f33c24b3815ecd560cee272786c3adfa5f31316d8b349bfade28 \ - --hash=sha256:72ac9762a9f8ce74c9eed4a4e74306f2f18613a6b71fa065495a67ac227b3056 \ - --hash=sha256:75133890e40d229d6c5837b0312abbe5bac1c342452cf0e12523477cd3aa21e7 \ - --hash=sha256:7605c1c32c3d6e8c990dd28a0970a3cbbf1429d5b92279e37fda05fb0c92190e \ - --hash=sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0 \ - --hash=sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079 \ - --hash=sha256:7a62cc23d754bb449d63ff35334acc9f5c02e6dae830d78dab4dd12b78a524f4 \ - --hash=sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9 \ - --hash=sha256:8f82125bc7203c5ae8633a7d5d20bcfdff0ba33e436e4ab0abc026a53a8960b7 \ - --hash=sha256:91505d3ddebf268bb1588eb0f63821f738d20e1e7f05d3c647a5ca900288760b \ - --hash=sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d \ - --hash=sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76 \ - --hash=sha256:98a3912194c079ef37e716ed228ae0dcb960992100461b704aea4e93af6b0bb9 \ - --hash=sha256:a3bcdde35d82ff385f4ede021df801b5c4a5bcdfb61ea87caabcebfc4945dc1b \ - --hash=sha256:a7fb111eef4d05909b82152721a59c1b14d0f365e2be4c742a473c5d7372f4f5 \ - --hash=sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5 \ - --hash=sha256:a8ef956fce64c8551221f395ba21d0724fed6b9b6242ca4f2f7beb4ce2f41997 \ - --hash=sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc \ - --hash=sha256:aea7c06667b987787c7d1f5e1dfcd70419b711cdb47d6b4bb4ad4b76777a0563 \ - --hash=sha256:aefe1a7cb852fa61150fcb21a8c8fcea7b58c4cb11fbe59c97a0a4b31cae3c8c \ - --hash=sha256:b12cb6527599808ada9eb2cd6e0e7d3d8f13fe7bbb01c6311255a15ded4c7ab4 \ - --hash=sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4 \ - --hash=sha256:b67319b4aef1a6c56576ff544b67a2a6fbd7eaee485b241cabf53115e8908b8f \ - --hash=sha256:b92b69441d1bd39f4940f9eadfa417a25862242ca2c396b406f9272ef09cdcaa \ - --hash=sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f \ - --hash=sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4 \ - --hash=sha256:c6364038c519dffdbe07e3cf42e6a7f8b90c275d4d1617a69bb59734c1a2d571 \ - --hash=sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d \ - --hash=sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de \ - --hash=sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd \ - --hash=sha256:d2ed1b3cb9ff1c10e6e8b00941bb2e5bb568b307bfc6b17dffbbe8be5eecba86 \ - --hash=sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82 \ - --hash=sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f \ - --hash=sha256:de5b4e1088523e2b6f730d0509a9a813355b7f5659d70eb4f319c76beea2e250 \ - --hash=sha256:df53330a3bff250f10472ce96a9af28628ff1f4efc51ccba351a8820bca2a8ba \ - --hash=sha256:e094ec83694b59d263802ed03a8384594fcce477ce484b0cbcd0008a211ca751 \ - --hash=sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff \ - --hash=sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c \ - --hash=sha256:ecf4c4b83f1ab3d5a7ace10bafcb6f11df6156857a3c418244cef41ca9fa3e44 \ - --hash=sha256:ef5a7178fcc73b7d8c07229e89f8eb45b2908a9238eb90dcfc46571ccf0383b8 \ - --hash=sha256:f5cb182f6396706dc6cc1896dd02b1c889d644c081b0cdec38747573db88a7d7 \ - --hash=sha256:fd3be6481ef54b8cfd0e1e953323b7aa9d9789b94842d0e5b142ef4bb7999539 +lxml==6.0.0 \ + --hash=sha256:013090383863b72c62a702d07678b658fa2567aa58d373d963cca245b017e065 \ + --hash=sha256:032e65120339d44cdc3efc326c9f660f5f7205f3a535c1fdbf898b29ea01fb72 \ + --hash=sha256:0e32698462aacc5c1cf6bdfebc9c781821b7e74c79f13e5ffc8bfe27c42b1abf \ + --hash=sha256:1676b56d48048a62ef77a250428d1f31f610763636e0784ba67a9740823988ca \ + --hash=sha256:1fa377b827ca2023244a06554c6e7dc6828a10aaf74ca41965c5d8a4925aebb4 \ + --hash=sha256:219e0431ea8006e15005767f0351e3f7f9143e793e58519dc97fe9e07fae5563 \ + --hash=sha256:21db1ec5525780fd07251636eb5f7acb84003e9382c72c18c542a87c416ade03 \ + --hash=sha256:246b40f8a4aec341cbbf52617cad8ab7c888d944bfe12a6abd2b1f6cfb6f6082 \ + --hash=sha256:2793a627e95d119e9f1e19720730472f5543a6d84c50ea33313ce328d870f2dd \ + --hash=sha256:2930aa001a3776c3e2601cb8e0a15d21b8270528d89cc308be4843ade546b9ab \ + --hash=sha256:2ae06fbab4f1bb7db4f7c8ca9897dc8db4447d1a2b9bee78474ad403437bcc29 \ + --hash=sha256:2b4790b558bee331a933e08883c423f65bbcd07e278f91b2272489e31ab1e2b4 \ + --hash=sha256:2cfcf84f1defed7e5798ef4f88aa25fcc52d279be731ce904789aa7ccfb7e8d2 \ + --hash=sha256:2dd1cc3ea7e60bfb31ff32cafe07e24839df573a5e7c2d33304082a5019bcd58 \ + --hash=sha256:2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e \ + --hash=sha256:310b719b695b3dd442cdfbbe64936b2f2e231bb91d998e99e6f0daf991a3eba3 \ + --hash=sha256:34190a1ec4f1e84af256495436b2d196529c3f2094f0af80202947567fdbf2e7 \ + --hash=sha256:35bc626eec405f745199200ccb5c6b36f202675d204aa29bb52e27ba2b71dea8 \ + --hash=sha256:36531f81c8214e293097cd2b7873f178997dae33d3667caaae8bdfb9666b76c0 \ + --hash=sha256:390240baeb9f415a82eefc2e13285016f9c8b5ad71ec80574ae8fa9605093cd7 \ + --hash=sha256:40442e2a4456e9910875ac12951476d36c0870dcb38a68719f8c4686609897c4 \ + --hash=sha256:43cfbb7db02b30ad3926e8fceaef260ba2fb7df787e38fa2df890c1ca7966c3b \ + --hash=sha256:43fe5af2d590bf4691531b1d9a2495d7aab2090547eaacd224a3afec95706d76 \ + --hash=sha256:46b9ed911f36bfeb6338e0b482e7fe7c27d362c52fde29f221fddbc9ee2227e7 \ + --hash=sha256:4d23854ecf381ab1facc8f353dcd9adeddef3652268ee75297c1164c987c11dc \ + --hash=sha256:4ee56288d0df919e4aac43b539dd0e34bb55d6a12a6562038e8d6f3ed07f9e36 \ + --hash=sha256:51a5e4c61a4541bd1cd3ba74766d0c9b6c12d6a1a4964ef60026832aac8e79b3 \ + --hash=sha256:522fe7abb41309e9543b0d9b8b434f2b630c5fdaf6482bee642b34c8c70079c8 \ + --hash=sha256:54c4855eabd9fc29707d30141be99e5cd1102e7d2258d2892314cf4c110726c3 \ + --hash=sha256:5592401cdf3dc682194727c1ddaa8aa0f3ddc57ca64fd03226a430b955eab6f6 \ + --hash=sha256:58ffd35bd5425c3c3b9692d078bf7ab851441434531a7e517c4984d5634cd65b \ + --hash=sha256:5967fe415b1920a3877a4195e9a2b779249630ee49ece22021c690320ff07452 \ + --hash=sha256:5fcd7d3b1d8ecb91445bd71b9c88bdbeae528fefee4f379895becfc72298d181 \ + --hash=sha256:690b20e3388a7ec98e899fd54c924e50ba6693874aa65ef9cb53de7f7de9d64a \ + --hash=sha256:6da7cd4f405fd7db56e51e96bff0865b9853ae70df0e6720624049da76bde2da \ + --hash=sha256:7488a43033c958637b1a08cddc9188eb06d3ad36582cebc7d4815980b47e27ef \ + --hash=sha256:74e748012f8c19b47f7d6321ac929a9a94ee92ef12bc4298c47e8b7219b26541 \ + --hash=sha256:78718d8454a6e928470d511bf8ac93f469283a45c354995f7d19e77292f26108 \ + --hash=sha256:84ef591495ffd3f9dcabffd6391db7bb70d7230b5c35ef5148354a134f56f2be \ + --hash=sha256:8a2e76efbf8772add72d002d67a4c3d0958638696f541734304c7f28217a9cab \ + --hash=sha256:8cb26f51c82d77483cdcd2b4a53cda55bbee29b3c2f3ddeb47182a2a9064e4eb \ + --hash=sha256:9ab542c91f5a47aaa58abdd8ea84b498e8e49fe4b883d67800017757a3eb78e8 \ + --hash=sha256:9f4b481b6cc3a897adb4279216695150bbe7a44c03daba3c894f49d2037e0a24 \ + --hash=sha256:a52a4704811e2623b0324a18d41ad4b9fabf43ce5ff99b14e40a520e2190c851 \ + --hash=sha256:afd27d8629ae94c5d863e32ab0e1d5590371d296b87dae0a751fb22bf3685741 \ + --hash=sha256:b2d71cdefda9424adff9a3607ba5bbfc60ee972d73c21c7e3c19e71037574816 \ + --hash=sha256:b34339898bb556a2351a1830f88f751679f343eabf9cf05841c95b165152c9e7 \ + --hash=sha256:b8dd6dd0e9c1992613ccda2bcb74fc9d49159dbe0f0ca4753f37527749885c25 \ + --hash=sha256:bd5913b4972681ffc9718bc2d4c53cde39ef81415e1671ff93e9aa30b46595e7 \ + --hash=sha256:c16304bba98f48a28ae10e32a8e75c349dd742c45156f297e16eeb1ba9287a1f \ + --hash=sha256:c24b8efd9c0f62bad0439283c2c795ef916c5a6b75f03c17799775c7ae3c0c9e \ + --hash=sha256:c2a5e8d207311a0170aca0eb6b160af91adc29ec121832e4ac151a57743a1e1e \ + --hash=sha256:c86df1c9af35d903d2b52d22ea3e66db8058d21dc0f59842ca5deb0595921141 \ + --hash=sha256:ca50bd612438258a91b5b3788c6621c1f05c8c478e7951899f492be42defc0da \ + --hash=sha256:d18a25b19ca7307045581b18b3ec9ead2b1db5ccd8719c291f0cd0a5cec6cb81 \ + --hash=sha256:d4f0c66df4386b75d2ab1e20a489f30dc7fd9a06a896d64980541506086be1f1 \ + --hash=sha256:d7ae472f74afcc47320238b5dbfd363aba111a525943c8a34a1b657c6be934c3 \ + --hash=sha256:db0efd6bae1c4730b9c863fc4f5f3c0fa3e8f05cae2c44ae141cb9dfc7d091dc \ + --hash=sha256:dbdd7679a6f4f08152818043dbb39491d1af3332128b3752c3ec5cebc0011a72 \ + --hash=sha256:e2030956cf4886b10be9a0285c6802e078ec2391e1dd7ff3eb509c2c95a69b76 \ + --hash=sha256:f3389924581d9a770c6caa4df4e74b606180869043b9073e2cec324bad6e306e \ + --hash=sha256:f720a14aa102a38907c6d5030e3d66b3b680c3e6f6bc95473931ea3c00c59967 \ + --hash=sha256:f8d19565ae3eb956d84da3ef367aa7def14a2735d05bd275cd54c0301f0d0d6c # via # pyhanko # python-docx @@ -1032,9 +1030,9 @@ pathspec==0.12.1 \ # mkdocs # mkdocs-macros-plugin # mypy -phonenumbers==9.0.7 \ - --hash=sha256:306eb14d1eaeb82230a08aa1614d04c93322b65b1ded2fff585161ed7eca39fc \ - --hash=sha256:d4cc2aa36cbf9b0004c370f406d1510ddef56bba9e5f759471ef47e998d8a2f9 +phonenumbers==9.0.8 \ + --hash=sha256:16f03f2cf65b5eee99ed25827d810febcab92b5d76f977e425fcd2e4ca6d4865 \ + --hash=sha256:53d357111c0ead0d6408ae443613b18d3a053431ca1ddf7e881457c0969afcf9 # via hypha pillow==10.4.0 \ --hash=sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885 \ @@ -1259,9 +1257,9 @@ pymdown-extensions==10.16 \ # via # mkdocs-material # mkdocstrings -pypdf==5.6.1 \ - --hash=sha256:dde36cd67afe3afd733a562a0dd08a3c1dcdf01fe01de13785291319c8a883ff \ - --hash=sha256:ff09d03d37addbc40f75db3624997a660ff5fe41c61e7ae4db6828dc3f581e4d +pypdf==5.7.0 \ + --hash=sha256:203379453439f5b68b7a1cd43cdf4c5f7a02b84810cefa7f93a47b350aaaba48 \ + --hash=sha256:68c92f2e1aae878bab1150e74447f31ab3848b1c0a6f8becae9f0b1904460b6f # via xhtml2pdf pypng==0.20220715.0 \ --hash=sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c \ @@ -1374,9 +1372,9 @@ python-docx==1.1.2 \ # via # htmldocx # hypha -python-dotenv==1.1.0 \ - --hash=sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5 \ - --hash=sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d +python-dotenv==1.1.1 \ + --hash=sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc \ + --hash=sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab # via environs python3-openid==3.2.0 \ --hash=sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf \ @@ -1478,25 +1476,25 @@ rich==12.6.0 \ --hash=sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e \ --hash=sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0 # via dslr -ruff==0.12.0 \ - --hash=sha256:05ed0c914fabc602fc1f3b42c53aa219e5736cb030cdd85640c32dbc73da74a6 \ - --hash=sha256:07a7aa9b69ac3fcfda3c507916d5d1bca10821fe3797d46bad10f2c6de1edda0 \ - --hash=sha256:0c0758038f81beec8cc52ca22de9685b8ae7f7cc18c013ec2050012862cc9165 \ - --hash=sha256:139b3d28027987b78fc8d6cfb61165447bdf3740e650b7c480744873688808c2 \ - --hash=sha256:1e55e44e770e061f55a7dbc6e9aed47feea07731d809a3710feda2262d2d4d8a \ - --hash=sha256:3a9512af224b9ac4757f7010843771da6b2b0935a9e5e76bb407caa901a1a514 \ - --hash=sha256:4d047db3662418d4a848a3fdbfaf17488b34b62f527ed6f10cb8afd78135bc5c \ - --hash=sha256:5652a9ecdb308a1754d96a68827755f28d5dfb416b06f60fd9e13f26191a8848 \ - --hash=sha256:68853e8517b17bba004152aebd9dd77d5213e503a5f2789395b25f26acac0da4 \ - --hash=sha256:6a315992297a7435a66259073681bb0d8647a826b7a6de45c6934b2ca3a9ed51 \ - --hash=sha256:7162a4c816f8d1555eb195c46ae0bd819834d2a3f18f98cc63819a7b46f474fb \ - --hash=sha256:7d235618283718ee2fe14db07f954f9b2423700919dc688eacf3f8797a11315c \ - --hash=sha256:8cd24580405ad8c1cc64d61725bca091d6b6da7eb3d36f72cc605467069d7e8b \ - --hash=sha256:952d0630eae628250ab1c70a7fffb641b03e6b4a2d3f3ec6c1d19b4ab6c6c807 \ - --hash=sha256:b08df3d96db798e5beb488d4df03011874aff919a97dcc2dd8539bb2be5d6a88 \ - --hash=sha256:c021f04ea06966b02614d442e94071781c424ab8e02ec7af2f037b4c1e01cc82 \ - --hash=sha256:d00b7a157b8fb6d3827b49d3324da34a1e3f93492c1f97b08e222ad7e9b291e0 \ - --hash=sha256:e7731c3eec50af71597243bace7ec6104616ca56dda2b99c89935fe926bdcd48 +ruff==0.12.1 \ + --hash=sha256:069052605fe74c765a5b4272eb89880e0ff7a31e6c0dbf8767203c1fbd31c7ff \ + --hash=sha256:2be9d32a147f98a1972c1e4df9a6956d612ca5f5578536814372113d09a27a6c \ + --hash=sha256:49b7ce354eed2a322fbaea80168c902de9504e6e174fd501e9447cad0232f9e6 \ + --hash=sha256:6013a46d865111e2edb71ad692fbb8262e6c172587a57c0669332a449384a36b \ + --hash=sha256:6cc32e863adcf9e71690248607ccdf25252eeeab5193768e6873b901fd441fed \ + --hash=sha256:70d52a058c0e7b88b602f575d23596e89bd7d8196437a4148381a3f73fcd5010 \ + --hash=sha256:78ad09a022c64c13cc6077707f036bab0fac8cd7088772dcd1e5be21c5002efc \ + --hash=sha256:7fd49a4619f90d5afc65cf42e07b6ae98bb454fd5029d03b306bd9e2273d44cc \ + --hash=sha256:801d626de15e6bf988fbe7ce59b303a914ff9c616d5866f8c79eb5012720ae13 \ + --hash=sha256:806bbc17f1104fd57451a98a58df35388ee3ab422e029e8f5cf30aa4af2c138c \ + --hash=sha256:84d0a69d1e8d716dfeab22d8d5e7c786b73f2106429a933cee51d7b09f861d4e \ + --hash=sha256:9a256522893cb7e92bb1e1153283927f842dea2e48619c803243dccc8437b8be \ + --hash=sha256:9e1123b1c033f77bd2590e4c1fe7e8ea72ef990a85d2484351d408224d603013 \ + --hash=sha256:a684f125a4fec2d5a6501a466be3841113ba6847827be4573fddf8308b83477d \ + --hash=sha256:b3f75a19e03a4b0757d1412edb7f27cffb0c700365e9d6b60bc1b68d35bc89e0 \ + --hash=sha256:bdecdef753bf1e95797593007569d8e1697a54fca843d78f6862f7dc279e23bd \ + --hash=sha256:d973fa626d4c8267848755bd0414211a456e99e125dcab147f24daa9e991a245 \ + --hash=sha256:ed5af6aaaea20710e77698e2055b9ff9b3494891e1b24d26c07055459bb717e9 s3transfer==0.13.0 \ --hash=sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be \ --hash=sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177 @@ -1572,9 +1570,9 @@ social-auth-app-django==5.4.3 \ --hash=sha256:d1f4286d5ca1e512c9b2f686e7ecb2a0128148f1a33d853b69dc07b58508362e \ --hash=sha256:db70b972faeb10ee1ec83d0dc7dbd0558d5f5830417bba317b712b10ff58d031 # via hypha -social-auth-core==4.6.1 \ - --hash=sha256:1019fe2f7fe30f9ff7d15c04a32c15324ecdbd59f62fbe829031dab74071a21a \ - --hash=sha256:563510844ccc043a727b120fe57726860c93158d4304fafa2c1e122f2deb4fd3 +social-auth-core==4.7.0 \ + --hash=sha256:2bba127c7b7166a81085ddb0c248d93751b3bc3cdab8569f62d9f70c6bc4ed40 \ + --hash=sha256:9eef9b49c332d1a3265b37dcc698a7ace97c3fc59df2d874b51576d11d31f6a6 # via social-auth-app-django soupsieve==2.7 \ --hash=sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4 \ @@ -1744,9 +1742,9 @@ uritools==5.0.0 \ --hash=sha256:68180cad154062bd5b5d9ffcdd464f8de6934414b25462ae807b00b8df9345de \ --hash=sha256:cead3a49ba8fbca3f91857343849d506d8639718f4a2e51b62e87393b493bd6f # via pyhanko-certvalidator -urllib3==2.2.3 \ - --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ - --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 +urllib3==2.5.0 \ + --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ + --hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc # via # botocore # django-anymail diff --git a/requirements/docs.txt b/requirements/docs.txt index 4088ef4169..c73b0a7b75 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -361,9 +361,9 @@ typing-extensions==4.14.0 ; python_full_version < '3.11' \ --hash=sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4 \ --hash=sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af # via mkdocstrings-python -urllib3==2.2.3 \ - --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ - --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 +urllib3==2.5.0 \ + --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ + --hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc # via requests watchdog==6.0.0 \ --hash=sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a \ diff --git a/requirements/prod.txt b/requirements/prod.txt index 8770c2d8fa..e85fbcc1a4 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -4,9 +4,9 @@ amqp==5.3.1 \ --hash=sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2 \ --hash=sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432 # via kombu -anyascii==0.3.2 \ - --hash=sha256:3b3beef6fc43d9036d3b0529050b0c48bfad8bc960e9e562d7223cfb94fe45d4 \ - --hash=sha256:9d5d32ef844fe225b8bc7cba7f950534fae4da27a9bf3a6bea2cb0ea46ce4730 +anyascii==0.3.3 \ + --hash=sha256:c94e9dd9d47b3d9494eca305fef9447d00b4bf1a32aff85aa746fa3ec7fb95c3 \ + --hash=sha256:f5ab5e53c8781a36b5a40e1296a0eeda2f48c649ef10c3921c1381b1d00dee7a # via wagtail anyio==4.9.0 \ --hash=sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028 \ @@ -72,19 +72,20 @@ beautifulsoup4==4.11.2 \ --hash=sha256:0e79446b10b3ecb499c1556f7e228a53e64a2bfcebd455f370d8927cb5b59e39 \ --hash=sha256:bc4bdda6717de5a2987436fb8d72f45dc90dd856bdfd512a1314ce90349a0106 # via + # html-diff # htmldocx # wagtail billiard==4.2.1 \ --hash=sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f \ --hash=sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb # via celery -boto3==1.38.41 \ - --hash=sha256:6119e9f272b9f004f052ca78ce94d3fe10198bc159ae808f75c0e1b9c07518bd \ - --hash=sha256:c6710fc533c8e1f5d1f025c74ffe1222c3659094cd51c076ec50c201a54c8f22 +boto3==1.38.46 \ + --hash=sha256:9c8e88a32a6465e5905308708cff5b17547117f06982908bdfdb0108b4a65079 \ + --hash=sha256:d1ca2b53138afd0341e1962bd52be6071ab7a63c5b4f89228c5ef8942c40c852 # via hypha -botocore==1.38.41 \ - --hash=sha256:06069a06f1352accb1f6c9505d6e323753627112be80a9d2e057c6d9c9779ffd \ - --hash=sha256:98e3fed636ebb519320c4b2d078db6fa6099b052b4bb9b5c66632a5a7fe72507 +botocore==1.38.46 \ + --hash=sha256:8798e5a418c27cf93195b077153644aea44cb171fcd56edc1ecebaa1e49e226e \ + --hash=sha256:89ca782ffbf2e8769ca9c89234cfa5ca577f1987d07d913ee3c68c4776b1eb5b # via # boto3 # s3transfer @@ -223,9 +224,9 @@ click-didyoumean==0.3.1 \ --hash=sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463 \ --hash=sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c # via celery -click-plugins==1.1.1 \ - --hash=sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b \ - --hash=sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8 +click-plugins==1.1.1.2 \ + --hash=sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6 \ + --hash=sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261 # via celery click-repl==0.3.0 \ --hash=sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9 \ @@ -303,6 +304,7 @@ django==4.2.23 \ # dj-database-url # django-anymail # django-basic-auth-ip-whitelist + # django-cotton # django-extensions # django-filter # django-formtools @@ -341,6 +343,10 @@ django-basic-auth-ip-whitelist==0.8.0 \ --hash=sha256:e4e46c2c59b4dde3a318d8812b6640b4a714bc2d1a0647854dead7743f1202ee \ --hash=sha256:edcff4ad789c9cf0c335c12366d5356f1f07d44172c2ecbfa5cb8ec914ea8252 # via hypha +django-cotton==2.1.2 \ + --hash=sha256:8492cb7cfe881455a1b9dfaaaec2d1943494a1d3d2e2066ac7da6ce31afceef3 \ + --hash=sha256:ad467f725239bf43004dad87dfc70f95c08d96efde4166d4bfb815e7cb72c56f + # via hypha django-countries==7.6.1 \ --hash=sha256:1ed20842fe0f6194f91faca21076649513846a8787c9eb5aeec3cbe1656b8acc \ --hash=sha256:c772d4e3e54afcc5f97a018544e96f246c6d9f1db51898ab0c15cd57e19437cf @@ -378,9 +384,9 @@ django-hijack==3.7.2 \ --hash=sha256:dc834a015082dd2d49afd13da6cf6f571ce1a16894d6070887261a37633f8d06 \ --hash=sha256:eb02d285ec1564bfa77ac2e73b9bca28848caa7b04c1e1eef3d573353eb9efaa # via hypha -django-htmx==1.23.1 \ - --hash=sha256:45febb80d2e85ee1da01dca61429d6f835ef176949cda4ecc5ae2e729d2ff53d \ - --hash=sha256:6a23ee1e74f54a28eca4ccb48191a585529fbad5cbd5b5c3d8ec1a16b8557090 +django-htmx==1.23.2 \ + --hash=sha256:65a8c8825fcae983b94aedce26af96a70717ab185d55cdb8a7a4bb68863ab079 \ + --hash=sha256:c288fe92bdcfa7c2ed9665d6d23cc55c6693a7cc8d22cf0a01e1e38318874030 # via hypha django-modelcluster==6.4 \ --hash=sha256:0102d00e6b884721ba21e32edb716548e0dead7880e130aa2e04854bd384a42f \ @@ -497,6 +503,10 @@ heroicons==2.11.0 \ --hash=sha256:36fed4e7a2fc134f70fd22597a73012b74904cec19968f85a5bad8ae97fb7cc2 \ --hash=sha256:68d8c754076b0c12f7f60157bcc47fb89135ccb4f0f7d3ac53791546132bf92d # via hypha +html-diff==0.4.1 \ + --hash=sha256:4260ad08d80a043f34a45721d429d3462ec2738b9002c7e5bd75040bdcd40528 \ + --hash=sha256:b64d90514abecd13702b936ec4221aa103f4f0df96427bf8387bb18ca6c0ab74 + # via hypha html5lib==1.1 \ --hash=sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d \ --hash=sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f @@ -540,82 +550,70 @@ lark==1.2.2 \ --hash=sha256:c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c \ --hash=sha256:ca807d0162cd16cef15a8feecb862d7319e7a09bdb13aef927968e45040fed80 # via hypha -lxml==5.4.0 \ - --hash=sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5 \ - --hash=sha256:0a01ce7d8479dce84fc03324e3b0c9c90b1ece9a9bb6a1b6c9025e7e4520e78c \ - --hash=sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b \ - --hash=sha256:0cef4feae82709eed352cd7e97ae062ef6ae9c7b5dbe3663f104cd2c0e8d94ba \ - --hash=sha256:0ea0252b51d296a75f6118ed0d8696888e7403408ad42345d7dfd0d1e93309a7 \ - --hash=sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422 \ - --hash=sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8 \ - --hash=sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a \ - --hash=sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982 \ - --hash=sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8 \ - --hash=sha256:1b717b00a71b901b4667226bba282dd462c42ccf618ade12f9ba3674e1fabc55 \ - --hash=sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2 \ - --hash=sha256:20e16c08254b9b6466526bc1828d9370ee6c0d60a4b64836bc3ac2917d1e16df \ - --hash=sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551 \ - --hash=sha256:27a9ded0f0b52098ff89dd4c418325b987feed2ea5cc86e8860b0f844285d740 \ - --hash=sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60 \ - --hash=sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e \ - --hash=sha256:3a3178b4873df8ef9457a4875703488eb1622632a9cee6d76464b60e90adbfcd \ - --hash=sha256:3b9c2754cef6963f3408ab381ea55f47dabc6f78f4b8ebb0f0b25cf1ac1f7609 \ - --hash=sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20 \ - --hash=sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61 \ - --hash=sha256:4329422de653cdb2b72afa39b0aa04252fca9071550044904b2e7036d9d97fe4 \ - --hash=sha256:43d549b876ce64aa18b2328faff70f5877f8c6dede415f80a2f799d31644d776 \ - --hash=sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779 \ - --hash=sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c \ - --hash=sha256:4b7ce10634113651d6f383aa712a194179dcd496bd8c41e191cec2099fa09de5 \ - --hash=sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f \ - --hash=sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54 \ - --hash=sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e \ - --hash=sha256:53370c26500d22b45182f98847243efb518d268374a9570409d2e2276232fd37 \ - --hash=sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7 \ - --hash=sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7 \ - --hash=sha256:696ea9e87442467819ac22394ca36cb3d01848dad1be6fac3fb612d3bd5a12cf \ - --hash=sha256:6ef80aeac414f33c24b3815ecd560cee272786c3adfa5f31316d8b349bfade28 \ - --hash=sha256:72ac9762a9f8ce74c9eed4a4e74306f2f18613a6b71fa065495a67ac227b3056 \ - --hash=sha256:75133890e40d229d6c5837b0312abbe5bac1c342452cf0e12523477cd3aa21e7 \ - --hash=sha256:7605c1c32c3d6e8c990dd28a0970a3cbbf1429d5b92279e37fda05fb0c92190e \ - --hash=sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0 \ - --hash=sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079 \ - --hash=sha256:7a62cc23d754bb449d63ff35334acc9f5c02e6dae830d78dab4dd12b78a524f4 \ - --hash=sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9 \ - --hash=sha256:8f82125bc7203c5ae8633a7d5d20bcfdff0ba33e436e4ab0abc026a53a8960b7 \ - --hash=sha256:91505d3ddebf268bb1588eb0f63821f738d20e1e7f05d3c647a5ca900288760b \ - --hash=sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d \ - --hash=sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76 \ - --hash=sha256:98a3912194c079ef37e716ed228ae0dcb960992100461b704aea4e93af6b0bb9 \ - --hash=sha256:a3bcdde35d82ff385f4ede021df801b5c4a5bcdfb61ea87caabcebfc4945dc1b \ - --hash=sha256:a7fb111eef4d05909b82152721a59c1b14d0f365e2be4c742a473c5d7372f4f5 \ - --hash=sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5 \ - --hash=sha256:a8ef956fce64c8551221f395ba21d0724fed6b9b6242ca4f2f7beb4ce2f41997 \ - --hash=sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc \ - --hash=sha256:aea7c06667b987787c7d1f5e1dfcd70419b711cdb47d6b4bb4ad4b76777a0563 \ - --hash=sha256:aefe1a7cb852fa61150fcb21a8c8fcea7b58c4cb11fbe59c97a0a4b31cae3c8c \ - --hash=sha256:b12cb6527599808ada9eb2cd6e0e7d3d8f13fe7bbb01c6311255a15ded4c7ab4 \ - --hash=sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4 \ - --hash=sha256:b67319b4aef1a6c56576ff544b67a2a6fbd7eaee485b241cabf53115e8908b8f \ - --hash=sha256:b92b69441d1bd39f4940f9eadfa417a25862242ca2c396b406f9272ef09cdcaa \ - --hash=sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f \ - --hash=sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4 \ - --hash=sha256:c6364038c519dffdbe07e3cf42e6a7f8b90c275d4d1617a69bb59734c1a2d571 \ - --hash=sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d \ - --hash=sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de \ - --hash=sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd \ - --hash=sha256:d2ed1b3cb9ff1c10e6e8b00941bb2e5bb568b307bfc6b17dffbbe8be5eecba86 \ - --hash=sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82 \ - --hash=sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f \ - --hash=sha256:de5b4e1088523e2b6f730d0509a9a813355b7f5659d70eb4f319c76beea2e250 \ - --hash=sha256:df53330a3bff250f10472ce96a9af28628ff1f4efc51ccba351a8820bca2a8ba \ - --hash=sha256:e094ec83694b59d263802ed03a8384594fcce477ce484b0cbcd0008a211ca751 \ - --hash=sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff \ - --hash=sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c \ - --hash=sha256:ecf4c4b83f1ab3d5a7ace10bafcb6f11df6156857a3c418244cef41ca9fa3e44 \ - --hash=sha256:ef5a7178fcc73b7d8c07229e89f8eb45b2908a9238eb90dcfc46571ccf0383b8 \ - --hash=sha256:f5cb182f6396706dc6cc1896dd02b1c889d644c081b0cdec38747573db88a7d7 \ - --hash=sha256:fd3be6481ef54b8cfd0e1e953323b7aa9d9789b94842d0e5b142ef4bb7999539 +lxml==6.0.0 \ + --hash=sha256:013090383863b72c62a702d07678b658fa2567aa58d373d963cca245b017e065 \ + --hash=sha256:032e65120339d44cdc3efc326c9f660f5f7205f3a535c1fdbf898b29ea01fb72 \ + --hash=sha256:0e32698462aacc5c1cf6bdfebc9c781821b7e74c79f13e5ffc8bfe27c42b1abf \ + --hash=sha256:1676b56d48048a62ef77a250428d1f31f610763636e0784ba67a9740823988ca \ + --hash=sha256:1fa377b827ca2023244a06554c6e7dc6828a10aaf74ca41965c5d8a4925aebb4 \ + --hash=sha256:219e0431ea8006e15005767f0351e3f7f9143e793e58519dc97fe9e07fae5563 \ + --hash=sha256:21db1ec5525780fd07251636eb5f7acb84003e9382c72c18c542a87c416ade03 \ + --hash=sha256:246b40f8a4aec341cbbf52617cad8ab7c888d944bfe12a6abd2b1f6cfb6f6082 \ + --hash=sha256:2793a627e95d119e9f1e19720730472f5543a6d84c50ea33313ce328d870f2dd \ + --hash=sha256:2930aa001a3776c3e2601cb8e0a15d21b8270528d89cc308be4843ade546b9ab \ + --hash=sha256:2ae06fbab4f1bb7db4f7c8ca9897dc8db4447d1a2b9bee78474ad403437bcc29 \ + --hash=sha256:2b4790b558bee331a933e08883c423f65bbcd07e278f91b2272489e31ab1e2b4 \ + --hash=sha256:2cfcf84f1defed7e5798ef4f88aa25fcc52d279be731ce904789aa7ccfb7e8d2 \ + --hash=sha256:2dd1cc3ea7e60bfb31ff32cafe07e24839df573a5e7c2d33304082a5019bcd58 \ + --hash=sha256:2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e \ + --hash=sha256:310b719b695b3dd442cdfbbe64936b2f2e231bb91d998e99e6f0daf991a3eba3 \ + --hash=sha256:34190a1ec4f1e84af256495436b2d196529c3f2094f0af80202947567fdbf2e7 \ + --hash=sha256:35bc626eec405f745199200ccb5c6b36f202675d204aa29bb52e27ba2b71dea8 \ + --hash=sha256:36531f81c8214e293097cd2b7873f178997dae33d3667caaae8bdfb9666b76c0 \ + --hash=sha256:390240baeb9f415a82eefc2e13285016f9c8b5ad71ec80574ae8fa9605093cd7 \ + --hash=sha256:40442e2a4456e9910875ac12951476d36c0870dcb38a68719f8c4686609897c4 \ + --hash=sha256:43cfbb7db02b30ad3926e8fceaef260ba2fb7df787e38fa2df890c1ca7966c3b \ + --hash=sha256:43fe5af2d590bf4691531b1d9a2495d7aab2090547eaacd224a3afec95706d76 \ + --hash=sha256:46b9ed911f36bfeb6338e0b482e7fe7c27d362c52fde29f221fddbc9ee2227e7 \ + --hash=sha256:4d23854ecf381ab1facc8f353dcd9adeddef3652268ee75297c1164c987c11dc \ + --hash=sha256:4ee56288d0df919e4aac43b539dd0e34bb55d6a12a6562038e8d6f3ed07f9e36 \ + --hash=sha256:51a5e4c61a4541bd1cd3ba74766d0c9b6c12d6a1a4964ef60026832aac8e79b3 \ + --hash=sha256:522fe7abb41309e9543b0d9b8b434f2b630c5fdaf6482bee642b34c8c70079c8 \ + --hash=sha256:54c4855eabd9fc29707d30141be99e5cd1102e7d2258d2892314cf4c110726c3 \ + --hash=sha256:5592401cdf3dc682194727c1ddaa8aa0f3ddc57ca64fd03226a430b955eab6f6 \ + --hash=sha256:58ffd35bd5425c3c3b9692d078bf7ab851441434531a7e517c4984d5634cd65b \ + --hash=sha256:5967fe415b1920a3877a4195e9a2b779249630ee49ece22021c690320ff07452 \ + --hash=sha256:5fcd7d3b1d8ecb91445bd71b9c88bdbeae528fefee4f379895becfc72298d181 \ + --hash=sha256:690b20e3388a7ec98e899fd54c924e50ba6693874aa65ef9cb53de7f7de9d64a \ + --hash=sha256:6da7cd4f405fd7db56e51e96bff0865b9853ae70df0e6720624049da76bde2da \ + --hash=sha256:7488a43033c958637b1a08cddc9188eb06d3ad36582cebc7d4815980b47e27ef \ + --hash=sha256:74e748012f8c19b47f7d6321ac929a9a94ee92ef12bc4298c47e8b7219b26541 \ + --hash=sha256:78718d8454a6e928470d511bf8ac93f469283a45c354995f7d19e77292f26108 \ + --hash=sha256:84ef591495ffd3f9dcabffd6391db7bb70d7230b5c35ef5148354a134f56f2be \ + --hash=sha256:8a2e76efbf8772add72d002d67a4c3d0958638696f541734304c7f28217a9cab \ + --hash=sha256:8cb26f51c82d77483cdcd2b4a53cda55bbee29b3c2f3ddeb47182a2a9064e4eb \ + --hash=sha256:9ab542c91f5a47aaa58abdd8ea84b498e8e49fe4b883d67800017757a3eb78e8 \ + --hash=sha256:9f4b481b6cc3a897adb4279216695150bbe7a44c03daba3c894f49d2037e0a24 \ + --hash=sha256:a52a4704811e2623b0324a18d41ad4b9fabf43ce5ff99b14e40a520e2190c851 \ + --hash=sha256:afd27d8629ae94c5d863e32ab0e1d5590371d296b87dae0a751fb22bf3685741 \ + --hash=sha256:b2d71cdefda9424adff9a3607ba5bbfc60ee972d73c21c7e3c19e71037574816 \ + --hash=sha256:b34339898bb556a2351a1830f88f751679f343eabf9cf05841c95b165152c9e7 \ + --hash=sha256:b8dd6dd0e9c1992613ccda2bcb74fc9d49159dbe0f0ca4753f37527749885c25 \ + --hash=sha256:bd5913b4972681ffc9718bc2d4c53cde39ef81415e1671ff93e9aa30b46595e7 \ + --hash=sha256:c16304bba98f48a28ae10e32a8e75c349dd742c45156f297e16eeb1ba9287a1f \ + --hash=sha256:c24b8efd9c0f62bad0439283c2c795ef916c5a6b75f03c17799775c7ae3c0c9e \ + --hash=sha256:c2a5e8d207311a0170aca0eb6b160af91adc29ec121832e4ac151a57743a1e1e \ + --hash=sha256:c86df1c9af35d903d2b52d22ea3e66db8058d21dc0f59842ca5deb0595921141 \ + --hash=sha256:ca50bd612438258a91b5b3788c6621c1f05c8c478e7951899f492be42defc0da \ + --hash=sha256:d18a25b19ca7307045581b18b3ec9ead2b1db5ccd8719c291f0cd0a5cec6cb81 \ + --hash=sha256:d4f0c66df4386b75d2ab1e20a489f30dc7fd9a06a896d64980541506086be1f1 \ + --hash=sha256:d7ae472f74afcc47320238b5dbfd363aba111a525943c8a34a1b657c6be934c3 \ + --hash=sha256:db0efd6bae1c4730b9c863fc4f5f3c0fa3e8f05cae2c44ae141cb9dfc7d091dc \ + --hash=sha256:dbdd7679a6f4f08152818043dbb39491d1af3332128b3752c3ec5cebc0011a72 \ + --hash=sha256:e2030956cf4886b10be9a0285c6802e078ec2391e1dd7ff3eb509c2c95a69b76 \ + --hash=sha256:f3389924581d9a770c6caa4df4e74b606180869043b9073e2cec324bad6e306e \ + --hash=sha256:f720a14aa102a38907c6d5030e3d66b3b680c3e6f6bc95473931ea3c00c59967 \ + --hash=sha256:f8d19565ae3eb956d84da3ef367aa7def14a2735d05bd275cd54c0301f0d0d6c # via # pyhanko # python-docx @@ -680,9 +678,9 @@ packaging==25.0 \ # via # gunicorn # kombu -phonenumbers==9.0.7 \ - --hash=sha256:306eb14d1eaeb82230a08aa1614d04c93322b65b1ded2fff585161ed7eca39fc \ - --hash=sha256:d4cc2aa36cbf9b0004c370f406d1510ddef56bba9e5f759471ef47e998d8a2f9 +phonenumbers==9.0.8 \ + --hash=sha256:16f03f2cf65b5eee99ed25827d810febcab92b5d76f977e425fcd2e4ca6d4865 \ + --hash=sha256:53d357111c0ead0d6408ae443613b18d3a053431ca1ddf7e881457c0969afcf9 # via hypha pillow==10.4.0 \ --hash=sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885 \ @@ -880,9 +878,9 @@ pyjwt==2.10.1 \ --hash=sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953 \ --hash=sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb # via social-auth-core -pypdf==5.6.1 \ - --hash=sha256:dde36cd67afe3afd733a562a0dd08a3c1dcdf01fe01de13785291319c8a883ff \ - --hash=sha256:ff09d03d37addbc40f75db3624997a660ff5fe41c61e7ae4db6828dc3f581e4d +pypdf==5.7.0 \ + --hash=sha256:203379453439f5b68b7a1cd43cdf4c5f7a02b84810cefa7f93a47b350aaaba48 \ + --hash=sha256:68c92f2e1aae878bab1150e74447f31ab3848b1c0a6f8becae9f0b1904460b6f # via xhtml2pdf pypng==0.20220715.0 \ --hash=sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c \ @@ -971,9 +969,9 @@ python-docx==1.1.2 \ # via # htmldocx # hypha -python-dotenv==1.1.0 \ - --hash=sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5 \ - --hash=sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d +python-dotenv==1.1.1 \ + --hash=sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc \ + --hash=sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab # via environs python3-openid==3.2.0 \ --hash=sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf \ @@ -1123,9 +1121,9 @@ social-auth-app-django==5.4.3 \ --hash=sha256:d1f4286d5ca1e512c9b2f686e7ecb2a0128148f1a33d853b69dc07b58508362e \ --hash=sha256:db70b972faeb10ee1ec83d0dc7dbd0558d5f5830417bba317b712b10ff58d031 # via hypha -social-auth-core==4.6.1 \ - --hash=sha256:1019fe2f7fe30f9ff7d15c04a32c15324ecdbd59f62fbe829031dab74071a21a \ - --hash=sha256:563510844ccc043a727b120fe57726860c93158d4304fafa2c1e122f2deb4fd3 +social-auth-core==4.7.0 \ + --hash=sha256:2bba127c7b7166a81085ddb0c248d93751b3bc3cdab8569f62d9f70c6bc4ed40 \ + --hash=sha256:9eef9b49c332d1a3265b37dcc698a7ace97c3fc59df2d874b51576d11d31f6a6 # via social-auth-app-django soupsieve==2.7 \ --hash=sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4 \ @@ -1228,9 +1226,9 @@ uritools==5.0.0 \ --hash=sha256:68180cad154062bd5b5d9ffcdd464f8de6934414b25462ae807b00b8df9345de \ --hash=sha256:cead3a49ba8fbca3f91857343849d506d8639718f4a2e51b62e87393b493bd6f # via pyhanko-certvalidator -urllib3==2.2.3 \ - --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ - --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 +urllib3==2.5.0 \ + --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ + --hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc # via # botocore # django-anymail diff --git a/requirements/translate.txt b/requirements/translate.txt index e1ff738a6d..e375dce70d 100644 --- a/requirements/translate.txt +++ b/requirements/translate.txt @@ -560,7 +560,7 @@ typing-extensions==4.14.0 \ --hash=sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4 \ --hash=sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af # via torch -urllib3==2.2.3 \ - --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ - --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 +urllib3==2.5.0 \ + --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ + --hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc # via requests diff --git a/uv.lock b/uv.lock index 26c2ce4055..acbabd2151 100644 --- a/uv.lock +++ b/uv.lock @@ -21,11 +21,11 @@ wheels = [ [[package]] name = "anyascii" -version = "0.3.2" +version = "0.3.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/52/93b9ea99063f7cf37fb67f5e3f49480686cbe7f228c48b9d713326223b6e/anyascii-0.3.2.tar.gz", hash = "sha256:9d5d32ef844fe225b8bc7cba7f950534fae4da27a9bf3a6bea2cb0ea46ce4730", size = 214052, upload-time = "2023-03-16T00:24:42.431Z" } +sdist = { url = "https://files.pythonhosted.org/packages/db/ba/edebda727008390936da4a9bf677c19cd63b32d51e864656d2cbd1028e25/anyascii-0.3.3.tar.gz", hash = "sha256:c94e9dd9d47b3d9494eca305fef9447d00b4bf1a32aff85aa746fa3ec7fb95c3", size = 264680, upload-time = "2025-06-29T03:33:30.427Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/7b/a9a747e0632271d855da379532b05a62c58e979813814a57fa3b3afeb3a4/anyascii-0.3.2-py3-none-any.whl", hash = "sha256:3b3beef6fc43d9036d3b0529050b0c48bfad8bc960e9e562d7223cfb94fe45d4", size = 289923, upload-time = "2023-03-16T00:24:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/c2/76/783b75a21ce3563b8709050de030ae253853b147bd52e141edc1025aa268/anyascii-0.3.3-py3-none-any.whl", hash = "sha256:f5ab5e53c8781a36b5a40e1296a0eeda2f48c649ef10c3921c1381b1d00dee7a", size = 345090, upload-time = "2025-06-29T03:33:28.356Z" }, ] [[package]] @@ -178,30 +178,30 @@ wheels = [ [[package]] name = "boto3" -version = "1.38.41" +version = "1.38.46" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2f/3b/f421b30e32c33ce63f0de3b32ea12954039a4595c693db4ea4900babe742/boto3-1.38.41.tar.gz", hash = "sha256:c6710fc533c8e1f5d1f025c74ffe1222c3659094cd51c076ec50c201a54c8f22", size = 111835, upload-time = "2025-06-20T19:26:41.584Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/56/ca67d22364ce8f23b1885d9a1bae50d8005fa9b32ec0deddba0b19079b99/boto3-1.38.46.tar.gz", hash = "sha256:d1ca2b53138afd0341e1962bd52be6071ab7a63c5b4f89228c5ef8942c40c852", size = 111883, upload-time = "2025-06-27T20:18:17.096Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/bb/541825bf9811eb7fe13a357e691dc4cfead56a5fed4556aa101dc62e06ca/boto3-1.38.41-py3-none-any.whl", hash = "sha256:6119e9f272b9f004f052ca78ce94d3fe10198bc159ae808f75c0e1b9c07518bd", size = 139922, upload-time = "2025-06-20T19:26:39.963Z" }, + { url = "https://files.pythonhosted.org/packages/b6/13/0eb850c821a976346a905370bb30c86da7edc2bbc3977c445fffc6306032/boto3-1.38.46-py3-none-any.whl", hash = "sha256:9c8e88a32a6465e5905308708cff5b17547117f06982908bdfdb0108b4a65079", size = 139925, upload-time = "2025-06-27T20:18:15.366Z" }, ] [[package]] name = "botocore" -version = "1.38.41" +version = "1.38.46" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/46/cb33f5a0b00086a97c4eebbc4e0211fe85d66d45e53a9545b33805f25b31/botocore-1.38.41.tar.gz", hash = "sha256:98e3fed636ebb519320c4b2d078db6fa6099b052b4bb9b5c66632a5a7fe72507", size = 14031081, upload-time = "2025-06-20T19:26:31.365Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/5f/d76870e4399fbfc12aa5c3bb36029edfc1a434392afc70a343c9d7d96e90/botocore-1.38.46.tar.gz", hash = "sha256:8798e5a418c27cf93195b077153644aea44cb171fcd56edc1ecebaa1e49e226e", size = 14074340, upload-time = "2025-06-27T20:18:06.646Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/b7/37d9f1a633e72250408cb7d53d8915561ac6108b5c3a1973eb8f53ce2990/botocore-1.38.41-py3-none-any.whl", hash = "sha256:06069a06f1352accb1f6c9505d6e323753627112be80a9d2e057c6d9c9779ffd", size = 13690225, upload-time = "2025-06-20T19:26:26.014Z" }, + { url = "https://files.pythonhosted.org/packages/a4/00/dd90b7a0255587ba1c9754d32a221adb4a9022f181df3eef401b0b9fadfc/botocore-1.38.46-py3-none-any.whl", hash = "sha256:89ca782ffbf2e8769ca9c89234cfa5ca577f1987d07d913ee3c68c4776b1eb5b", size = 13736872, upload-time = "2025-06-27T20:18:00.901Z" }, ] [[package]] @@ -403,14 +403,14 @@ wheels = [ [[package]] name = "click-plugins" -version = "1.1.1" +version = "1.1.1.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5f/1d/45434f64ed749540af821fd7e42b8e4d23ac04b1eda7c26613288d6cd8a8/click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b", size = 8164, upload-time = "2019-04-04T04:27:04.82Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/a4/34847b59150da33690a36da3681d6bbc2ec14ee9a846bc30a6746e5984e4/click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261", size = 8343, upload-time = "2025-06-25T00:47:37.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/da/824b92d9942f4e472702488857914bdd50f73021efea15b4cad9aca8ecef/click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8", size = 7497, upload-time = "2019-04-04T04:27:03.36Z" }, + { url = "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6", size = 11051, upload-time = "2025-06-25T00:47:36.731Z" }, ] [[package]] @@ -690,6 +690,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e4/9d/1322dc4bce4982d1eadd3a62802c996ae0303aad13d9ad88c1d35025f73d/django_browser_reload-1.18.0-py3-none-any.whl", hash = "sha256:ed4cc2fb83c3bf6c30b54107a1a6736c0b896e62e4eba666d81005b9f2ecf6f8", size = 12230, upload-time = "2025-02-06T22:14:36.87Z" }, ] +[[package]] +name = "django-cotton" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/4e/e8be2accc5e10c899f4d22e6f64686b93733c5ac42524275e627cbf7314f/django_cotton-2.1.2.tar.gz", hash = "sha256:ad467f725239bf43004dad87dfc70f95c08d96efde4166d4bfb815e7cb72c56f", size = 23063, upload-time = "2025-05-11T21:43:58.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/2b/1285d050801ee92bfe408574954d26aaacbf67e1eb68946a78024fd3d0b8/django_cotton-2.1.2-py3-none-any.whl", hash = "sha256:8492cb7cfe881455a1b9dfaaaec2d1943494a1d3d2e2066ac7da6ce31afceef3", size = 22053, upload-time = "2025-05-11T21:43:56.978Z" }, +] + [[package]] name = "django-countries" version = "7.6.1" @@ -820,15 +832,15 @@ wheels = [ [[package]] name = "django-htmx" -version = "1.23.1" +version = "1.23.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, { name = "django" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/3a/ef8857b5fbd56c140c0b552100968a7d78f025019520e0f68b24a6a5556e/django_htmx-1.23.1.tar.gz", hash = "sha256:6a23ee1e74f54a28eca4ccb48191a585529fbad5cbd5b5c3d8ec1a16b8557090", size = 64256, upload-time = "2025-06-21T22:33:45.814Z" } +sdist = { url = "https://files.pythonhosted.org/packages/84/d4/1709593b01799c29c8d5a6f72973d787c8b881b0f8e2767b9e913fe2c688/django_htmx-1.23.2.tar.gz", hash = "sha256:65a8c8825fcae983b94aedce26af96a70717ab185d55cdb8a7a4bb68863ab079", size = 64415, upload-time = "2025-06-27T14:09:32.539Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/90/885aac4159be37926e38b8797fd9f2c102289271cfbcabf6f8d29bf12a3f/django_htmx-1.23.1-py3-none-any.whl", hash = "sha256:45febb80d2e85ee1da01dca61429d6f835ef176949cda4ecc5ae2e729d2ff53d", size = 61446, upload-time = "2025-06-21T22:33:44.26Z" }, + { url = "https://files.pythonhosted.org/packages/3c/84/d5b29c102743abd61e1852b619263c8938b8516c71a138f4053114270743/django_htmx-1.23.2-py3-none-any.whl", hash = "sha256:c288fe92bdcfa7c2ed9665d6d23cc55c6693a7cc8d22cf0a01e1e38318874030", size = 61503, upload-time = "2025-06-27T14:09:31.272Z" }, ] [[package]] @@ -1152,7 +1164,7 @@ name = "exceptiongroup" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } wheels = [ @@ -1318,6 +1330,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1f/7f/13cd798d180af4bf4c0ceddeefba2b864a63c71645abc0308b768d67bb81/hjson-3.1.0-py3-none-any.whl", hash = "sha256:65713cdcf13214fb554eb8b4ef803419733f4f5e551047c9b711098ab7186b89", size = 54018, upload-time = "2022-08-13T02:52:59.899Z" }, ] +[[package]] +name = "html-diff" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/b2/53c5b08a6af8b90213f45aad08ef6dc02a50bffc30f27b6093fb9d4f1bb9/html-diff-0.4.1.tar.gz", hash = "sha256:4260ad08d80a043f34a45721d429d3462ec2738b9002c7e5bd75040bdcd40528", size = 24461, upload-time = "2021-12-03T17:50:12.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/ea/2306cede5715f6203515f595b7c251c1a5ea083e5139be70c503962edff8/html_diff-0.4.1-py3-none-any.whl", hash = "sha256:b64d90514abecd13702b936ec4221aa103f4f0df96427bf8387bb18ca6c0ab74", size = 24174, upload-time = "2021-12-03T17:50:14.229Z" }, +] + [[package]] name = "html5lib" version = "1.1" @@ -1385,6 +1409,7 @@ dependencies = [ { name = "django" }, { name = "django-anymail" }, { name = "django-basic-auth-ip-whitelist" }, + { name = "django-cotton" }, { name = "django-countries" }, { name = "django-elevate" }, { name = "django-extensions" }, @@ -1410,6 +1435,7 @@ dependencies = [ { name = "environs" }, { name = "gunicorn" }, { name = "heroicons" }, + { name = "html-diff" }, { name = "htmldocx" }, { name = "lark" }, { name = "mistune" }, @@ -1483,6 +1509,7 @@ requires-dist = [ { name = "django", specifier = "~=4.2.2" }, { name = "django-anymail", specifier = "~=13.0" }, { name = "django-basic-auth-ip-whitelist", specifier = "~=0.8.0" }, + { name = "django-cotton", specifier = "~=2.1" }, { name = "django-countries", specifier = "~=7.6.1" }, { name = "django-elevate", specifier = "~=2.0.3" }, { name = "django-extensions", specifier = "~=3.2.3" }, @@ -1508,6 +1535,7 @@ requires-dist = [ { name = "environs", specifier = "~=14.1.1" }, { name = "gunicorn", specifier = "~=23.0.0" }, { name = "heroicons", specifier = "~=2.11.0" }, + { name = "html-diff", specifier = ">=0.4.1" }, { name = "htmldocx", specifier = "~=0.0.6" }, { name = "lark", specifier = "~=1.2.2" }, { name = "mistune", specifier = "~=3.1.3" }, @@ -1667,84 +1695,72 @@ wheels = [ [[package]] name = "lxml" -version = "5.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/76/3d/14e82fc7c8fb1b7761f7e748fd47e2ec8276d137b6acfe5a4bb73853e08f/lxml-5.4.0.tar.gz", hash = "sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd", size = 3679479, upload-time = "2025-04-23T01:50:29.322Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/1f/a3b6b74a451ceb84b471caa75c934d2430a4d84395d38ef201d539f38cd1/lxml-5.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c", size = 8076838, upload-time = "2025-04-23T01:44:29.325Z" }, - { url = "https://files.pythonhosted.org/packages/36/af/a567a55b3e47135b4d1f05a1118c24529104c003f95851374b3748139dc1/lxml-5.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7", size = 4381827, upload-time = "2025-04-23T01:44:33.345Z" }, - { url = "https://files.pythonhosted.org/packages/50/ba/4ee47d24c675932b3eb5b6de77d0f623c2db6dc466e7a1f199792c5e3e3a/lxml-5.4.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:696ea9e87442467819ac22394ca36cb3d01848dad1be6fac3fb612d3bd5a12cf", size = 5204098, upload-time = "2025-04-23T01:44:35.809Z" }, - { url = "https://files.pythonhosted.org/packages/f2/0f/b4db6dfebfefe3abafe360f42a3d471881687fd449a0b86b70f1f2683438/lxml-5.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ef80aeac414f33c24b3815ecd560cee272786c3adfa5f31316d8b349bfade28", size = 4930261, upload-time = "2025-04-23T01:44:38.271Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1f/0bb1bae1ce056910f8db81c6aba80fec0e46c98d77c0f59298c70cd362a3/lxml-5.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b9c2754cef6963f3408ab381ea55f47dabc6f78f4b8ebb0f0b25cf1ac1f7609", size = 5529621, upload-time = "2025-04-23T01:44:40.921Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/e7b66a533fc4a1e7fa63dd22a1ab2ec4d10319b909211181e1ab3e539295/lxml-5.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a62cc23d754bb449d63ff35334acc9f5c02e6dae830d78dab4dd12b78a524f4", size = 4983231, upload-time = "2025-04-23T01:44:43.871Z" }, - { url = "https://files.pythonhosted.org/packages/11/39/a38244b669c2d95a6a101a84d3c85ba921fea827e9e5483e93168bf1ccb2/lxml-5.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f82125bc7203c5ae8633a7d5d20bcfdff0ba33e436e4ab0abc026a53a8960b7", size = 5084279, upload-time = "2025-04-23T01:44:46.632Z" }, - { url = "https://files.pythonhosted.org/packages/db/64/48cac242347a09a07740d6cee7b7fd4663d5c1abd65f2e3c60420e231b27/lxml-5.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b67319b4aef1a6c56576ff544b67a2a6fbd7eaee485b241cabf53115e8908b8f", size = 4927405, upload-time = "2025-04-23T01:44:49.843Z" }, - { url = "https://files.pythonhosted.org/packages/98/89/97442835fbb01d80b72374f9594fe44f01817d203fa056e9906128a5d896/lxml-5.4.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:a8ef956fce64c8551221f395ba21d0724fed6b9b6242ca4f2f7beb4ce2f41997", size = 5550169, upload-time = "2025-04-23T01:44:52.791Z" }, - { url = "https://files.pythonhosted.org/packages/f1/97/164ca398ee654eb21f29c6b582685c6c6b9d62d5213abc9b8380278e9c0a/lxml-5.4.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:0a01ce7d8479dce84fc03324e3b0c9c90b1ece9a9bb6a1b6c9025e7e4520e78c", size = 5062691, upload-time = "2025-04-23T01:44:56.108Z" }, - { url = "https://files.pythonhosted.org/packages/d0/bc/712b96823d7feb53482d2e4f59c090fb18ec7b0d0b476f353b3085893cda/lxml-5.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:91505d3ddebf268bb1588eb0f63821f738d20e1e7f05d3c647a5ca900288760b", size = 5133503, upload-time = "2025-04-23T01:44:59.222Z" }, - { url = "https://files.pythonhosted.org/packages/d4/55/a62a39e8f9da2a8b6002603475e3c57c870cd9c95fd4b94d4d9ac9036055/lxml-5.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a3bcdde35d82ff385f4ede021df801b5c4a5bcdfb61ea87caabcebfc4945dc1b", size = 4999346, upload-time = "2025-04-23T01:45:02.088Z" }, - { url = "https://files.pythonhosted.org/packages/ea/47/a393728ae001b92bb1a9e095e570bf71ec7f7fbae7688a4792222e56e5b9/lxml-5.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aea7c06667b987787c7d1f5e1dfcd70419b711cdb47d6b4bb4ad4b76777a0563", size = 5627139, upload-time = "2025-04-23T01:45:04.582Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5f/9dcaaad037c3e642a7ea64b479aa082968de46dd67a8293c541742b6c9db/lxml-5.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7fb111eef4d05909b82152721a59c1b14d0f365e2be4c742a473c5d7372f4f5", size = 5465609, upload-time = "2025-04-23T01:45:07.649Z" }, - { url = "https://files.pythonhosted.org/packages/a7/0a/ebcae89edf27e61c45023005171d0ba95cb414ee41c045ae4caf1b8487fd/lxml-5.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43d549b876ce64aa18b2328faff70f5877f8c6dede415f80a2f799d31644d776", size = 5192285, upload-time = "2025-04-23T01:45:10.456Z" }, - { url = "https://files.pythonhosted.org/packages/42/ad/cc8140ca99add7d85c92db8b2354638ed6d5cc0e917b21d36039cb15a238/lxml-5.4.0-cp310-cp310-win32.whl", hash = "sha256:75133890e40d229d6c5837b0312abbe5bac1c342452cf0e12523477cd3aa21e7", size = 3477507, upload-time = "2025-04-23T01:45:12.474Z" }, - { url = "https://files.pythonhosted.org/packages/e9/39/597ce090da1097d2aabd2f9ef42187a6c9c8546d67c419ce61b88b336c85/lxml-5.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:de5b4e1088523e2b6f730d0509a9a813355b7f5659d70eb4f319c76beea2e250", size = 3805104, upload-time = "2025-04-23T01:45:15.104Z" }, - { url = "https://files.pythonhosted.org/packages/81/2d/67693cc8a605a12e5975380d7ff83020dcc759351b5a066e1cced04f797b/lxml-5.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:98a3912194c079ef37e716ed228ae0dcb960992100461b704aea4e93af6b0bb9", size = 8083240, upload-time = "2025-04-23T01:45:18.566Z" }, - { url = "https://files.pythonhosted.org/packages/73/53/b5a05ab300a808b72e848efd152fe9c022c0181b0a70b8bca1199f1bed26/lxml-5.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ea0252b51d296a75f6118ed0d8696888e7403408ad42345d7dfd0d1e93309a7", size = 4387685, upload-time = "2025-04-23T01:45:21.387Z" }, - { url = "https://files.pythonhosted.org/packages/d8/cb/1a3879c5f512bdcd32995c301886fe082b2edd83c87d41b6d42d89b4ea4d/lxml-5.4.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b92b69441d1bd39f4940f9eadfa417a25862242ca2c396b406f9272ef09cdcaa", size = 4991164, upload-time = "2025-04-23T01:45:23.849Z" }, - { url = "https://files.pythonhosted.org/packages/f9/94/bbc66e42559f9d04857071e3b3d0c9abd88579367fd2588a4042f641f57e/lxml-5.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20e16c08254b9b6466526bc1828d9370ee6c0d60a4b64836bc3ac2917d1e16df", size = 4746206, upload-time = "2025-04-23T01:45:26.361Z" }, - { url = "https://files.pythonhosted.org/packages/66/95/34b0679bee435da2d7cae895731700e519a8dfcab499c21662ebe671603e/lxml-5.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7605c1c32c3d6e8c990dd28a0970a3cbbf1429d5b92279e37fda05fb0c92190e", size = 5342144, upload-time = "2025-04-23T01:45:28.939Z" }, - { url = "https://files.pythonhosted.org/packages/e0/5d/abfcc6ab2fa0be72b2ba938abdae1f7cad4c632f8d552683ea295d55adfb/lxml-5.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ecf4c4b83f1ab3d5a7ace10bafcb6f11df6156857a3c418244cef41ca9fa3e44", size = 4825124, upload-time = "2025-04-23T01:45:31.361Z" }, - { url = "https://files.pythonhosted.org/packages/5a/78/6bd33186c8863b36e084f294fc0a5e5eefe77af95f0663ef33809cc1c8aa/lxml-5.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cef4feae82709eed352cd7e97ae062ef6ae9c7b5dbe3663f104cd2c0e8d94ba", size = 4876520, upload-time = "2025-04-23T01:45:34.191Z" }, - { url = "https://files.pythonhosted.org/packages/3b/74/4d7ad4839bd0fc64e3d12da74fc9a193febb0fae0ba6ebd5149d4c23176a/lxml-5.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:df53330a3bff250f10472ce96a9af28628ff1f4efc51ccba351a8820bca2a8ba", size = 4765016, upload-time = "2025-04-23T01:45:36.7Z" }, - { url = "https://files.pythonhosted.org/packages/24/0d/0a98ed1f2471911dadfc541003ac6dd6879fc87b15e1143743ca20f3e973/lxml-5.4.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:aefe1a7cb852fa61150fcb21a8c8fcea7b58c4cb11fbe59c97a0a4b31cae3c8c", size = 5362884, upload-time = "2025-04-23T01:45:39.291Z" }, - { url = "https://files.pythonhosted.org/packages/48/de/d4f7e4c39740a6610f0f6959052b547478107967362e8424e1163ec37ae8/lxml-5.4.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ef5a7178fcc73b7d8c07229e89f8eb45b2908a9238eb90dcfc46571ccf0383b8", size = 4902690, upload-time = "2025-04-23T01:45:42.386Z" }, - { url = "https://files.pythonhosted.org/packages/07/8c/61763abd242af84f355ca4ef1ee096d3c1b7514819564cce70fd18c22e9a/lxml-5.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d2ed1b3cb9ff1c10e6e8b00941bb2e5bb568b307bfc6b17dffbbe8be5eecba86", size = 4944418, upload-time = "2025-04-23T01:45:46.051Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c5/6d7e3b63e7e282619193961a570c0a4c8a57fe820f07ca3fe2f6bd86608a/lxml-5.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:72ac9762a9f8ce74c9eed4a4e74306f2f18613a6b71fa065495a67ac227b3056", size = 4827092, upload-time = "2025-04-23T01:45:48.943Z" }, - { url = "https://files.pythonhosted.org/packages/71/4a/e60a306df54680b103348545706a98a7514a42c8b4fbfdcaa608567bb065/lxml-5.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f5cb182f6396706dc6cc1896dd02b1c889d644c081b0cdec38747573db88a7d7", size = 5418231, upload-time = "2025-04-23T01:45:51.481Z" }, - { url = "https://files.pythonhosted.org/packages/27/f2/9754aacd6016c930875854f08ac4b192a47fe19565f776a64004aa167521/lxml-5.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:3a3178b4873df8ef9457a4875703488eb1622632a9cee6d76464b60e90adbfcd", size = 5261798, upload-time = "2025-04-23T01:45:54.146Z" }, - { url = "https://files.pythonhosted.org/packages/38/a2/0c49ec6941428b1bd4f280650d7b11a0f91ace9db7de32eb7aa23bcb39ff/lxml-5.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e094ec83694b59d263802ed03a8384594fcce477ce484b0cbcd0008a211ca751", size = 4988195, upload-time = "2025-04-23T01:45:56.685Z" }, - { url = "https://files.pythonhosted.org/packages/7a/75/87a3963a08eafc46a86c1131c6e28a4de103ba30b5ae903114177352a3d7/lxml-5.4.0-cp311-cp311-win32.whl", hash = "sha256:4329422de653cdb2b72afa39b0aa04252fca9071550044904b2e7036d9d97fe4", size = 3474243, upload-time = "2025-04-23T01:45:58.863Z" }, - { url = "https://files.pythonhosted.org/packages/fa/f9/1f0964c4f6c2be861c50db380c554fb8befbea98c6404744ce243a3c87ef/lxml-5.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd3be6481ef54b8cfd0e1e953323b7aa9d9789b94842d0e5b142ef4bb7999539", size = 3815197, upload-time = "2025-04-23T01:46:01.096Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4c/d101ace719ca6a4ec043eb516fcfcb1b396a9fccc4fcd9ef593df34ba0d5/lxml-5.4.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4", size = 8127392, upload-time = "2025-04-23T01:46:04.09Z" }, - { url = "https://files.pythonhosted.org/packages/11/84/beddae0cec4dd9ddf46abf156f0af451c13019a0fa25d7445b655ba5ccb7/lxml-5.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d", size = 4415103, upload-time = "2025-04-23T01:46:07.227Z" }, - { url = "https://files.pythonhosted.org/packages/d0/25/d0d93a4e763f0462cccd2b8a665bf1e4343dd788c76dcfefa289d46a38a9/lxml-5.4.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779", size = 5024224, upload-time = "2025-04-23T01:46:10.237Z" }, - { url = "https://files.pythonhosted.org/packages/31/ce/1df18fb8f7946e7f3388af378b1f34fcf253b94b9feedb2cec5969da8012/lxml-5.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e", size = 4769913, upload-time = "2025-04-23T01:46:12.757Z" }, - { url = "https://files.pythonhosted.org/packages/4e/62/f4a6c60ae7c40d43657f552f3045df05118636be1165b906d3423790447f/lxml-5.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9", size = 5290441, upload-time = "2025-04-23T01:46:16.037Z" }, - { url = "https://files.pythonhosted.org/packages/9e/aa/04f00009e1e3a77838c7fc948f161b5d2d5de1136b2b81c712a263829ea4/lxml-5.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5", size = 4820165, upload-time = "2025-04-23T01:46:19.137Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/e0b2f61fa2404bf0f1fdf1898377e5bd1b74cc9b2cf2c6ba8509b8f27990/lxml-5.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5", size = 4932580, upload-time = "2025-04-23T01:46:21.963Z" }, - { url = "https://files.pythonhosted.org/packages/24/a2/8263f351b4ffe0ed3e32ea7b7830f845c795349034f912f490180d88a877/lxml-5.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4", size = 4759493, upload-time = "2025-04-23T01:46:24.316Z" }, - { url = "https://files.pythonhosted.org/packages/05/00/41db052f279995c0e35c79d0f0fc9f8122d5b5e9630139c592a0b58c71b4/lxml-5.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e", size = 5324679, upload-time = "2025-04-23T01:46:27.097Z" }, - { url = "https://files.pythonhosted.org/packages/1d/be/ee99e6314cdef4587617d3b3b745f9356d9b7dd12a9663c5f3b5734b64ba/lxml-5.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7", size = 4890691, upload-time = "2025-04-23T01:46:30.009Z" }, - { url = "https://files.pythonhosted.org/packages/ad/36/239820114bf1d71f38f12208b9c58dec033cbcf80101cde006b9bde5cffd/lxml-5.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079", size = 4955075, upload-time = "2025-04-23T01:46:32.33Z" }, - { url = "https://files.pythonhosted.org/packages/d4/e1/1b795cc0b174efc9e13dbd078a9ff79a58728a033142bc6d70a1ee8fc34d/lxml-5.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20", size = 4838680, upload-time = "2025-04-23T01:46:34.852Z" }, - { url = "https://files.pythonhosted.org/packages/72/48/3c198455ca108cec5ae3662ae8acd7fd99476812fd712bb17f1b39a0b589/lxml-5.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8", size = 5391253, upload-time = "2025-04-23T01:46:37.608Z" }, - { url = "https://files.pythonhosted.org/packages/d6/10/5bf51858971c51ec96cfc13e800a9951f3fd501686f4c18d7d84fe2d6352/lxml-5.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f", size = 5261651, upload-time = "2025-04-23T01:46:40.183Z" }, - { url = "https://files.pythonhosted.org/packages/2b/11/06710dd809205377da380546f91d2ac94bad9ff735a72b64ec029f706c85/lxml-5.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc", size = 5024315, upload-time = "2025-04-23T01:46:43.333Z" }, - { url = "https://files.pythonhosted.org/packages/f5/b0/15b6217834b5e3a59ebf7f53125e08e318030e8cc0d7310355e6edac98ef/lxml-5.4.0-cp312-cp312-win32.whl", hash = "sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f", size = 3486149, upload-time = "2025-04-23T01:46:45.684Z" }, - { url = "https://files.pythonhosted.org/packages/91/1e/05ddcb57ad2f3069101611bd5f5084157d90861a2ef460bf42f45cced944/lxml-5.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2", size = 3817095, upload-time = "2025-04-23T01:46:48.521Z" }, - { url = "https://files.pythonhosted.org/packages/87/cb/2ba1e9dd953415f58548506fa5549a7f373ae55e80c61c9041b7fd09a38a/lxml-5.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0", size = 8110086, upload-time = "2025-04-23T01:46:52.218Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3e/6602a4dca3ae344e8609914d6ab22e52ce42e3e1638c10967568c5c1450d/lxml-5.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de", size = 4404613, upload-time = "2025-04-23T01:46:55.281Z" }, - { url = "https://files.pythonhosted.org/packages/4c/72/bf00988477d3bb452bef9436e45aeea82bb40cdfb4684b83c967c53909c7/lxml-5.4.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76", size = 5012008, upload-time = "2025-04-23T01:46:57.817Z" }, - { url = "https://files.pythonhosted.org/packages/92/1f/93e42d93e9e7a44b2d3354c462cd784dbaaf350f7976b5d7c3f85d68d1b1/lxml-5.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d", size = 4760915, upload-time = "2025-04-23T01:47:00.745Z" }, - { url = "https://files.pythonhosted.org/packages/45/0b/363009390d0b461cf9976a499e83b68f792e4c32ecef092f3f9ef9c4ba54/lxml-5.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422", size = 5283890, upload-time = "2025-04-23T01:47:04.702Z" }, - { url = "https://files.pythonhosted.org/packages/19/dc/6056c332f9378ab476c88e301e6549a0454dbee8f0ae16847414f0eccb74/lxml-5.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551", size = 4812644, upload-time = "2025-04-23T01:47:07.833Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/f8c66bbb23ecb9048a46a5ef9b495fd23f7543df642dabeebcb2eeb66592/lxml-5.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c", size = 4921817, upload-time = "2025-04-23T01:47:10.317Z" }, - { url = "https://files.pythonhosted.org/packages/04/57/2e537083c3f381f83d05d9b176f0d838a9e8961f7ed8ddce3f0217179ce3/lxml-5.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff", size = 4753916, upload-time = "2025-04-23T01:47:12.823Z" }, - { url = "https://files.pythonhosted.org/packages/d8/80/ea8c4072109a350848f1157ce83ccd9439601274035cd045ac31f47f3417/lxml-5.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60", size = 5289274, upload-time = "2025-04-23T01:47:15.916Z" }, - { url = "https://files.pythonhosted.org/packages/b3/47/c4be287c48cdc304483457878a3f22999098b9a95f455e3c4bda7ec7fc72/lxml-5.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8", size = 4874757, upload-time = "2025-04-23T01:47:19.793Z" }, - { url = "https://files.pythonhosted.org/packages/2f/04/6ef935dc74e729932e39478e44d8cfe6a83550552eaa072b7c05f6f22488/lxml-5.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982", size = 4947028, upload-time = "2025-04-23T01:47:22.401Z" }, - { url = "https://files.pythonhosted.org/packages/cb/f9/c33fc8daa373ef8a7daddb53175289024512b6619bc9de36d77dca3df44b/lxml-5.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61", size = 4834487, upload-time = "2025-04-23T01:47:25.513Z" }, - { url = "https://files.pythonhosted.org/packages/8d/30/fc92bb595bcb878311e01b418b57d13900f84c2b94f6eca9e5073ea756e6/lxml-5.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54", size = 5381688, upload-time = "2025-04-23T01:47:28.454Z" }, - { url = "https://files.pythonhosted.org/packages/43/d1/3ba7bd978ce28bba8e3da2c2e9d5ae3f8f521ad3f0ca6ea4788d086ba00d/lxml-5.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b", size = 5242043, upload-time = "2025-04-23T01:47:31.208Z" }, - { url = "https://files.pythonhosted.org/packages/ee/cd/95fa2201041a610c4d08ddaf31d43b98ecc4b1d74b1e7245b1abdab443cb/lxml-5.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a", size = 5021569, upload-time = "2025-04-23T01:47:33.805Z" }, - { url = "https://files.pythonhosted.org/packages/2d/a6/31da006fead660b9512d08d23d31e93ad3477dd47cc42e3285f143443176/lxml-5.4.0-cp313-cp313-win32.whl", hash = "sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82", size = 3485270, upload-time = "2025-04-23T01:47:36.133Z" }, - { url = "https://files.pythonhosted.org/packages/fc/14/c115516c62a7d2499781d2d3d7215218c0731b2c940753bf9f9b7b73924d/lxml-5.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f", size = 3814606, upload-time = "2025-04-23T01:47:39.028Z" }, - { url = "https://files.pythonhosted.org/packages/c6/b0/e4d1cbb8c078bc4ae44de9c6a79fec4e2b4151b1b4d50af71d799e76b177/lxml-5.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1b717b00a71b901b4667226bba282dd462c42ccf618ade12f9ba3674e1fabc55", size = 3892319, upload-time = "2025-04-23T01:49:22.069Z" }, - { url = "https://files.pythonhosted.org/packages/5b/aa/e2bdefba40d815059bcb60b371a36fbfcce970a935370e1b367ba1cc8f74/lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27a9ded0f0b52098ff89dd4c418325b987feed2ea5cc86e8860b0f844285d740", size = 4211614, upload-time = "2025-04-23T01:49:24.599Z" }, - { url = "https://files.pythonhosted.org/packages/3c/5f/91ff89d1e092e7cfdd8453a939436ac116db0a665e7f4be0cd8e65c7dc5a/lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7ce10634113651d6f383aa712a194179dcd496bd8c41e191cec2099fa09de5", size = 4306273, upload-time = "2025-04-23T01:49:27.355Z" }, - { url = "https://files.pythonhosted.org/packages/be/7c/8c3f15df2ca534589717bfd19d1e3482167801caedfa4d90a575facf68a6/lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53370c26500d22b45182f98847243efb518d268374a9570409d2e2276232fd37", size = 4208552, upload-time = "2025-04-23T01:49:29.949Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d8/9567afb1665f64d73fc54eb904e418d1138d7f011ed00647121b4dd60b38/lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c6364038c519dffdbe07e3cf42e6a7f8b90c275d4d1617a69bb59734c1a2d571", size = 4331091, upload-time = "2025-04-23T01:49:32.842Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ab/fdbbd91d8d82bf1a723ba88ec3e3d76c022b53c391b0c13cad441cdb8f9e/lxml-5.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b12cb6527599808ada9eb2cd6e0e7d3d8f13fe7bbb01c6311255a15ded4c7ab4", size = 3487862, upload-time = "2025-04-23T01:49:36.296Z" }, +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/ed/60eb6fa2923602fba988d9ca7c5cdbd7cf25faa795162ed538b527a35411/lxml-6.0.0.tar.gz", hash = "sha256:032e65120339d44cdc3efc326c9f660f5f7205f3a535c1fdbf898b29ea01fb72", size = 4096938, upload-time = "2025-06-26T16:28:19.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/e9/9c3ca02fbbb7585116c2e274b354a2d92b5c70561687dd733ec7b2018490/lxml-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:35bc626eec405f745199200ccb5c6b36f202675d204aa29bb52e27ba2b71dea8", size = 8399057, upload-time = "2025-06-26T16:25:02.169Z" }, + { url = "https://files.pythonhosted.org/packages/86/25/10a6e9001191854bf283515020f3633b1b1f96fd1b39aa30bf8fff7aa666/lxml-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:246b40f8a4aec341cbbf52617cad8ab7c888d944bfe12a6abd2b1f6cfb6f6082", size = 4569676, upload-time = "2025-06-26T16:25:05.431Z" }, + { url = "https://files.pythonhosted.org/packages/f5/a5/378033415ff61d9175c81de23e7ad20a3ffb614df4ffc2ffc86bc6746ffd/lxml-6.0.0-cp310-cp310-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:2793a627e95d119e9f1e19720730472f5543a6d84c50ea33313ce328d870f2dd", size = 5291361, upload-time = "2025-06-26T16:25:07.901Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a6/19c87c4f3b9362b08dc5452a3c3bce528130ac9105fc8fff97ce895ce62e/lxml-6.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:46b9ed911f36bfeb6338e0b482e7fe7c27d362c52fde29f221fddbc9ee2227e7", size = 5008290, upload-time = "2025-06-28T18:47:13.196Z" }, + { url = "https://files.pythonhosted.org/packages/09/d1/e9b7ad4b4164d359c4d87ed8c49cb69b443225cb495777e75be0478da5d5/lxml-6.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b4790b558bee331a933e08883c423f65bbcd07e278f91b2272489e31ab1e2b4", size = 5163192, upload-time = "2025-06-28T18:47:17.279Z" }, + { url = "https://files.pythonhosted.org/packages/56/d6/b3eba234dc1584744b0b374a7f6c26ceee5dc2147369a7e7526e25a72332/lxml-6.0.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2030956cf4886b10be9a0285c6802e078ec2391e1dd7ff3eb509c2c95a69b76", size = 5076973, upload-time = "2025-06-26T16:25:10.936Z" }, + { url = "https://files.pythonhosted.org/packages/8e/47/897142dd9385dcc1925acec0c4afe14cc16d310ce02c41fcd9010ac5d15d/lxml-6.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d23854ecf381ab1facc8f353dcd9adeddef3652268ee75297c1164c987c11dc", size = 5297795, upload-time = "2025-06-26T16:25:14.282Z" }, + { url = "https://files.pythonhosted.org/packages/fb/db/551ad84515c6f415cea70193a0ff11d70210174dc0563219f4ce711655c6/lxml-6.0.0-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:43fe5af2d590bf4691531b1d9a2495d7aab2090547eaacd224a3afec95706d76", size = 4776547, upload-time = "2025-06-26T16:25:17.123Z" }, + { url = "https://files.pythonhosted.org/packages/e0/14/c4a77ab4f89aaf35037a03c472f1ccc54147191888626079bd05babd6808/lxml-6.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74e748012f8c19b47f7d6321ac929a9a94ee92ef12bc4298c47e8b7219b26541", size = 5124904, upload-time = "2025-06-26T16:25:19.485Z" }, + { url = "https://files.pythonhosted.org/packages/70/b4/12ae6a51b8da106adec6a2e9c60f532350a24ce954622367f39269e509b1/lxml-6.0.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:43cfbb7db02b30ad3926e8fceaef260ba2fb7df787e38fa2df890c1ca7966c3b", size = 4805804, upload-time = "2025-06-26T16:25:21.949Z" }, + { url = "https://files.pythonhosted.org/packages/a9/b6/2e82d34d49f6219cdcb6e3e03837ca5fb8b7f86c2f35106fb8610ac7f5b8/lxml-6.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:34190a1ec4f1e84af256495436b2d196529c3f2094f0af80202947567fdbf2e7", size = 5323477, upload-time = "2025-06-26T16:25:24.475Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e6/b83ddc903b05cd08a5723fefd528eee84b0edd07bdf87f6c53a1fda841fd/lxml-6.0.0-cp310-cp310-win32.whl", hash = "sha256:5967fe415b1920a3877a4195e9a2b779249630ee49ece22021c690320ff07452", size = 3613840, upload-time = "2025-06-26T16:25:27.345Z" }, + { url = "https://files.pythonhosted.org/packages/40/af/874fb368dd0c663c030acb92612341005e52e281a102b72a4c96f42942e1/lxml-6.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:f3389924581d9a770c6caa4df4e74b606180869043b9073e2cec324bad6e306e", size = 3993584, upload-time = "2025-06-26T16:25:29.391Z" }, + { url = "https://files.pythonhosted.org/packages/4a/f4/d296bc22c17d5607653008f6dd7b46afdfda12efd31021705b507df652bb/lxml-6.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:522fe7abb41309e9543b0d9b8b434f2b630c5fdaf6482bee642b34c8c70079c8", size = 3681400, upload-time = "2025-06-26T16:25:31.421Z" }, + { url = "https://files.pythonhosted.org/packages/7c/23/828d4cc7da96c611ec0ce6147bbcea2fdbde023dc995a165afa512399bbf/lxml-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ee56288d0df919e4aac43b539dd0e34bb55d6a12a6562038e8d6f3ed07f9e36", size = 8438217, upload-time = "2025-06-26T16:25:34.349Z" }, + { url = "https://files.pythonhosted.org/packages/f1/33/5ac521212c5bcb097d573145d54b2b4a3c9766cda88af5a0e91f66037c6e/lxml-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8dd6dd0e9c1992613ccda2bcb74fc9d49159dbe0f0ca4753f37527749885c25", size = 4590317, upload-time = "2025-06-26T16:25:38.103Z" }, + { url = "https://files.pythonhosted.org/packages/2b/2e/45b7ca8bee304c07f54933c37afe7dd4d39ff61ba2757f519dcc71bc5d44/lxml-6.0.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:d7ae472f74afcc47320238b5dbfd363aba111a525943c8a34a1b657c6be934c3", size = 5221628, upload-time = "2025-06-26T16:25:40.878Z" }, + { url = "https://files.pythonhosted.org/packages/32/23/526d19f7eb2b85da1f62cffb2556f647b049ebe2a5aa8d4d41b1fb2c7d36/lxml-6.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5592401cdf3dc682194727c1ddaa8aa0f3ddc57ca64fd03226a430b955eab6f6", size = 4949429, upload-time = "2025-06-28T18:47:20.046Z" }, + { url = "https://files.pythonhosted.org/packages/ac/cc/f6be27a5c656a43a5344e064d9ae004d4dcb1d3c9d4f323c8189ddfe4d13/lxml-6.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58ffd35bd5425c3c3b9692d078bf7ab851441434531a7e517c4984d5634cd65b", size = 5087909, upload-time = "2025-06-28T18:47:22.834Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e6/8ec91b5bfbe6972458bc105aeb42088e50e4b23777170404aab5dfb0c62d/lxml-6.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f720a14aa102a38907c6d5030e3d66b3b680c3e6f6bc95473931ea3c00c59967", size = 5031713, upload-time = "2025-06-26T16:25:43.226Z" }, + { url = "https://files.pythonhosted.org/packages/33/cf/05e78e613840a40e5be3e40d892c48ad3e475804db23d4bad751b8cadb9b/lxml-6.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2a5e8d207311a0170aca0eb6b160af91adc29ec121832e4ac151a57743a1e1e", size = 5232417, upload-time = "2025-06-26T16:25:46.111Z" }, + { url = "https://files.pythonhosted.org/packages/ac/8c/6b306b3e35c59d5f0b32e3b9b6b3b0739b32c0dc42a295415ba111e76495/lxml-6.0.0-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:2dd1cc3ea7e60bfb31ff32cafe07e24839df573a5e7c2d33304082a5019bcd58", size = 4681443, upload-time = "2025-06-26T16:25:48.837Z" }, + { url = "https://files.pythonhosted.org/packages/59/43/0bd96bece5f7eea14b7220476835a60d2b27f8e9ca99c175f37c085cb154/lxml-6.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cfcf84f1defed7e5798ef4f88aa25fcc52d279be731ce904789aa7ccfb7e8d2", size = 5074542, upload-time = "2025-06-26T16:25:51.65Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3d/32103036287a8ca012d8518071f8852c68f2b3bfe048cef2a0202eb05910/lxml-6.0.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a52a4704811e2623b0324a18d41ad4b9fabf43ce5ff99b14e40a520e2190c851", size = 4729471, upload-time = "2025-06-26T16:25:54.571Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a8/7be5d17df12d637d81854bd8648cd329f29640a61e9a72a3f77add4a311b/lxml-6.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c16304bba98f48a28ae10e32a8e75c349dd742c45156f297e16eeb1ba9287a1f", size = 5256285, upload-time = "2025-06-26T16:25:56.997Z" }, + { url = "https://files.pythonhosted.org/packages/cd/d0/6cb96174c25e0d749932557c8d51d60c6e292c877b46fae616afa23ed31a/lxml-6.0.0-cp311-cp311-win32.whl", hash = "sha256:f8d19565ae3eb956d84da3ef367aa7def14a2735d05bd275cd54c0301f0d0d6c", size = 3612004, upload-time = "2025-06-26T16:25:59.11Z" }, + { url = "https://files.pythonhosted.org/packages/ca/77/6ad43b165dfc6dead001410adeb45e88597b25185f4479b7ca3b16a5808f/lxml-6.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b2d71cdefda9424adff9a3607ba5bbfc60ee972d73c21c7e3c19e71037574816", size = 4003470, upload-time = "2025-06-26T16:26:01.655Z" }, + { url = "https://files.pythonhosted.org/packages/a0/bc/4c50ec0eb14f932a18efc34fc86ee936a66c0eb5f2fe065744a2da8a68b2/lxml-6.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:8a2e76efbf8772add72d002d67a4c3d0958638696f541734304c7f28217a9cab", size = 3682477, upload-time = "2025-06-26T16:26:03.808Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/d01d735c298d7e0ddcedf6f028bf556577e5ab4f4da45175ecd909c79378/lxml-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78718d8454a6e928470d511bf8ac93f469283a45c354995f7d19e77292f26108", size = 8429515, upload-time = "2025-06-26T16:26:06.776Z" }, + { url = "https://files.pythonhosted.org/packages/06/37/0e3eae3043d366b73da55a86274a590bae76dc45aa004b7042e6f97803b1/lxml-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:84ef591495ffd3f9dcabffd6391db7bb70d7230b5c35ef5148354a134f56f2be", size = 4601387, upload-time = "2025-06-26T16:26:09.511Z" }, + { url = "https://files.pythonhosted.org/packages/a3/28/e1a9a881e6d6e29dda13d633885d13acb0058f65e95da67841c8dd02b4a8/lxml-6.0.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:2930aa001a3776c3e2601cb8e0a15d21b8270528d89cc308be4843ade546b9ab", size = 5228928, upload-time = "2025-06-26T16:26:12.337Z" }, + { url = "https://files.pythonhosted.org/packages/9a/55/2cb24ea48aa30c99f805921c1c7860c1f45c0e811e44ee4e6a155668de06/lxml-6.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:219e0431ea8006e15005767f0351e3f7f9143e793e58519dc97fe9e07fae5563", size = 4952289, upload-time = "2025-06-28T18:47:25.602Z" }, + { url = "https://files.pythonhosted.org/packages/31/c0/b25d9528df296b9a3306ba21ff982fc5b698c45ab78b94d18c2d6ae71fd9/lxml-6.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bd5913b4972681ffc9718bc2d4c53cde39ef81415e1671ff93e9aa30b46595e7", size = 5111310, upload-time = "2025-06-28T18:47:28.136Z" }, + { url = "https://files.pythonhosted.org/packages/e9/af/681a8b3e4f668bea6e6514cbcb297beb6de2b641e70f09d3d78655f4f44c/lxml-6.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:390240baeb9f415a82eefc2e13285016f9c8b5ad71ec80574ae8fa9605093cd7", size = 5025457, upload-time = "2025-06-26T16:26:15.068Z" }, + { url = "https://files.pythonhosted.org/packages/69/f8/693b1a10a891197143c0673fcce5b75fc69132afa81a36e4568c12c8faba/lxml-6.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ca50bd612438258a91b5b3788c6621c1f05c8c478e7951899f492be42defc0da", size = 5257565, upload-time = "2025-06-26T16:26:17.906Z" }, + { url = "https://files.pythonhosted.org/packages/a8/96/e08ff98f2c6426c98c8964513c5dab8d6eb81dadcd0af6f0c538ada78d33/lxml-6.0.0-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:c24b8efd9c0f62bad0439283c2c795ef916c5a6b75f03c17799775c7ae3c0c9e", size = 4713390, upload-time = "2025-06-26T16:26:20.292Z" }, + { url = "https://files.pythonhosted.org/packages/a8/83/6184aba6cc94d7413959f6f8f54807dc318fdcd4985c347fe3ea6937f772/lxml-6.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:afd27d8629ae94c5d863e32ab0e1d5590371d296b87dae0a751fb22bf3685741", size = 5066103, upload-time = "2025-06-26T16:26:22.765Z" }, + { url = "https://files.pythonhosted.org/packages/ee/01/8bf1f4035852d0ff2e36a4d9aacdbcc57e93a6cd35a54e05fa984cdf73ab/lxml-6.0.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:54c4855eabd9fc29707d30141be99e5cd1102e7d2258d2892314cf4c110726c3", size = 4791428, upload-time = "2025-06-26T16:26:26.461Z" }, + { url = "https://files.pythonhosted.org/packages/5c/f7/5495829a864bc5f8b0798d2b52a807c89966523140f3d6fa3a58ab6720ea/lxml-6.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36531f81c8214e293097cd2b7873f178997dae33d3667caaae8bdfb9666b76c0", size = 5281290, upload-time = "2025-06-26T16:26:29.406Z" }, + { url = "https://files.pythonhosted.org/packages/79/56/6b8edb79d9ed294ccc4e881f4db1023af56ba451909b9ce79f2a2cd7c532/lxml-6.0.0-cp312-cp312-win32.whl", hash = "sha256:690b20e3388a7ec98e899fd54c924e50ba6693874aa65ef9cb53de7f7de9d64a", size = 3613495, upload-time = "2025-06-26T16:26:31.588Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1e/cc32034b40ad6af80b6fd9b66301fc0f180f300002e5c3eb5a6110a93317/lxml-6.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:310b719b695b3dd442cdfbbe64936b2f2e231bb91d998e99e6f0daf991a3eba3", size = 4014711, upload-time = "2025-06-26T16:26:33.723Z" }, + { url = "https://files.pythonhosted.org/packages/55/10/dc8e5290ae4c94bdc1a4c55865be7e1f31dfd857a88b21cbba68b5fea61b/lxml-6.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:8cb26f51c82d77483cdcd2b4a53cda55bbee29b3c2f3ddeb47182a2a9064e4eb", size = 3674431, upload-time = "2025-06-26T16:26:35.959Z" }, + { url = "https://files.pythonhosted.org/packages/79/21/6e7c060822a3c954ff085e5e1b94b4a25757c06529eac91e550f3f5cd8b8/lxml-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6da7cd4f405fd7db56e51e96bff0865b9853ae70df0e6720624049da76bde2da", size = 8414372, upload-time = "2025-06-26T16:26:39.079Z" }, + { url = "https://files.pythonhosted.org/packages/a4/f6/051b1607a459db670fc3a244fa4f06f101a8adf86cda263d1a56b3a4f9d5/lxml-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b34339898bb556a2351a1830f88f751679f343eabf9cf05841c95b165152c9e7", size = 4593940, upload-time = "2025-06-26T16:26:41.891Z" }, + { url = "https://files.pythonhosted.org/packages/8e/74/dd595d92a40bda3c687d70d4487b2c7eff93fd63b568acd64fedd2ba00fe/lxml-6.0.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:51a5e4c61a4541bd1cd3ba74766d0c9b6c12d6a1a4964ef60026832aac8e79b3", size = 5214329, upload-time = "2025-06-26T16:26:44.669Z" }, + { url = "https://files.pythonhosted.org/packages/52/46/3572761efc1bd45fcafb44a63b3b0feeb5b3f0066886821e94b0254f9253/lxml-6.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d18a25b19ca7307045581b18b3ec9ead2b1db5ccd8719c291f0cd0a5cec6cb81", size = 4947559, upload-time = "2025-06-28T18:47:31.091Z" }, + { url = "https://files.pythonhosted.org/packages/94/8a/5e40de920e67c4f2eef9151097deb9b52d86c95762d8ee238134aff2125d/lxml-6.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d4f0c66df4386b75d2ab1e20a489f30dc7fd9a06a896d64980541506086be1f1", size = 5102143, upload-time = "2025-06-28T18:47:33.612Z" }, + { url = "https://files.pythonhosted.org/packages/7c/4b/20555bdd75d57945bdabfbc45fdb1a36a1a0ff9eae4653e951b2b79c9209/lxml-6.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f4b481b6cc3a897adb4279216695150bbe7a44c03daba3c894f49d2037e0a24", size = 5021931, upload-time = "2025-06-26T16:26:47.503Z" }, + { url = "https://files.pythonhosted.org/packages/d4/dd/39c8507c16db6031f8c1ddf70ed95dbb0a6d466a40002a3522c128aba472/lxml-6.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae06fbab4f1bb7db4f7c8ca9897dc8db4447d1a2b9bee78474ad403437bcc29", size = 5247467, upload-time = "2025-06-26T16:26:49.998Z" }, + { url = "https://files.pythonhosted.org/packages/4d/56/732d49def0631ad633844cfb2664563c830173a98d5efd9b172e89a4800d/lxml-6.0.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:1fa377b827ca2023244a06554c6e7dc6828a10aaf74ca41965c5d8a4925aebb4", size = 4720601, upload-time = "2025-06-26T16:26:52.564Z" }, + { url = "https://files.pythonhosted.org/packages/8f/7f/6b956fab95fa73462bca25d1ea7fc8274ddf68fb8e60b78d56c03b65278e/lxml-6.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1676b56d48048a62ef77a250428d1f31f610763636e0784ba67a9740823988ca", size = 5060227, upload-time = "2025-06-26T16:26:55.054Z" }, + { url = "https://files.pythonhosted.org/packages/97/06/e851ac2924447e8b15a294855caf3d543424364a143c001014d22c8ca94c/lxml-6.0.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0e32698462aacc5c1cf6bdfebc9c781821b7e74c79f13e5ffc8bfe27c42b1abf", size = 4790637, upload-time = "2025-06-26T16:26:57.384Z" }, + { url = "https://files.pythonhosted.org/packages/52/03/0e764ce00b95e008d76b99d432f1807f3574fb2945b496a17807a1645dbd/lxml-6.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7488a43033c958637b1a08cddc9188eb06d3ad36582cebc7d4815980b47e27ef", size = 5272430, upload-time = "2025-06-26T16:27:00.031Z" }, + { url = "https://files.pythonhosted.org/packages/5f/01/d48cc141bc47bc1644d20fe97bbd5e8afb30415ec94f146f2f76d0d9d098/lxml-6.0.0-cp313-cp313-win32.whl", hash = "sha256:5fcd7d3b1d8ecb91445bd71b9c88bdbeae528fefee4f379895becfc72298d181", size = 3612896, upload-time = "2025-06-26T16:27:04.251Z" }, + { url = "https://files.pythonhosted.org/packages/f4/87/6456b9541d186ee7d4cb53bf1b9a0d7f3b1068532676940fdd594ac90865/lxml-6.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e", size = 4013132, upload-time = "2025-06-26T16:27:06.415Z" }, + { url = "https://files.pythonhosted.org/packages/b7/42/85b3aa8f06ca0d24962f8100f001828e1f1f1a38c954c16e71154ed7d53a/lxml-6.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:21db1ec5525780fd07251636eb5f7acb84003e9382c72c18c542a87c416ade03", size = 3672642, upload-time = "2025-06-26T16:27:09.888Z" }, + { url = "https://files.pythonhosted.org/packages/66/e1/2c22a3cff9e16e1d717014a1e6ec2bf671bf56ea8716bb64466fcf820247/lxml-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:dbdd7679a6f4f08152818043dbb39491d1af3332128b3752c3ec5cebc0011a72", size = 3898804, upload-time = "2025-06-26T16:27:59.751Z" }, + { url = "https://files.pythonhosted.org/packages/2b/3a/d68cbcb4393a2a0a867528741fafb7ce92dac5c9f4a1680df98e5e53e8f5/lxml-6.0.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:40442e2a4456e9910875ac12951476d36c0870dcb38a68719f8c4686609897c4", size = 4216406, upload-time = "2025-06-28T18:47:45.518Z" }, + { url = "https://files.pythonhosted.org/packages/15/8f/d9bfb13dff715ee3b2a1ec2f4a021347ea3caf9aba93dea0cfe54c01969b/lxml-6.0.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db0efd6bae1c4730b9c863fc4f5f3c0fa3e8f05cae2c44ae141cb9dfc7d091dc", size = 4326455, upload-time = "2025-06-28T18:47:48.411Z" }, + { url = "https://files.pythonhosted.org/packages/01/8b/fde194529ee8a27e6f5966d7eef05fa16f0567e4a8e8abc3b855ef6b3400/lxml-6.0.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9ab542c91f5a47aaa58abdd8ea84b498e8e49fe4b883d67800017757a3eb78e8", size = 4268788, upload-time = "2025-06-26T16:28:02.776Z" }, + { url = "https://files.pythonhosted.org/packages/99/a8/3b8e2581b4f8370fc9e8dc343af4abdfadd9b9229970fc71e67bd31c7df1/lxml-6.0.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:013090383863b72c62a702d07678b658fa2567aa58d373d963cca245b017e065", size = 4411394, upload-time = "2025-06-26T16:28:05.179Z" }, + { url = "https://files.pythonhosted.org/packages/e7/a5/899a4719e02ff4383f3f96e5d1878f882f734377f10dfb69e73b5f223e44/lxml-6.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c86df1c9af35d903d2b52d22ea3e66db8058d21dc0f59842ca5deb0595921141", size = 3517946, upload-time = "2025-06-26T16:28:07.665Z" }, ] [[package]] @@ -2503,11 +2519,11 @@ wheels = [ [[package]] name = "phonenumbers" -version = "9.0.7" +version = "9.0.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/8c/2c09b844e819e70c261ad79cc302a5e307d97cb0ab70c227031d8ad72871/phonenumbers-9.0.7.tar.gz", hash = "sha256:d4cc2aa36cbf9b0004c370f406d1510ddef56bba9e5f759471ef47e998d8a2f9", size = 2297250, upload-time = "2025-06-09T06:01:09.224Z" } +sdist = { url = "https://files.pythonhosted.org/packages/86/3a/8dd1d5e15ac347db59a43fc623638d8088f9d511e7f8d8eec7d90b3abb4f/phonenumbers-9.0.8.tar.gz", hash = "sha256:16f03f2cf65b5eee99ed25827d810febcab92b5d76f977e425fcd2e4ca6d4865", size = 2297504, upload-time = "2025-06-25T05:41:38.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/d6/71ed688698834669f61dbba51601a27b62c1a7f5f868444f973a3fd33dc8/phonenumbers-9.0.7-py2.py3-none-any.whl", hash = "sha256:306eb14d1eaeb82230a08aa1614d04c93322b65b1ded2fff585161ed7eca39fc", size = 2583027, upload-time = "2025-06-09T06:01:04.772Z" }, + { url = "https://files.pythonhosted.org/packages/48/2e/23c1eca9f73e332b947c66c431690672783cf49b8418aa650ce06bdf6115/phonenumbers-9.0.8-py2.py3-none-any.whl", hash = "sha256:53d357111c0ead0d6408ae443613b18d3a053431ca1ddf7e881457c0969afcf9", size = 2583252, upload-time = "2025-06-25T05:41:34.815Z" }, ] [[package]] @@ -2861,14 +2877,14 @@ wheels = [ [[package]] name = "pypdf" -version = "5.6.1" +version = "5.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f7/8e/9d9346c36bb02fc6d6e5c5412dcc104e422738c3391ef32032bcb7fb183f/pypdf-5.6.1.tar.gz", hash = "sha256:dde36cd67afe3afd733a562a0dd08a3c1dcdf01fe01de13785291319c8a883ff", size = 5025128, upload-time = "2025-06-22T11:05:25.587Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/42/fbc37af367b20fa6c53da81b1780025f6046a0fac8cbf0663a17e743b033/pypdf-5.7.0.tar.gz", hash = "sha256:68c92f2e1aae878bab1150e74447f31ab3848b1c0a6f8becae9f0b1904460b6f", size = 5026120, upload-time = "2025-06-29T08:49:48.305Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/16/a5619a9d9bd4601126b95a9026eccfe4ebb74d725b7fdf624680e5a1f502/pypdf-5.6.1-py3-none-any.whl", hash = "sha256:ff09d03d37addbc40f75db3624997a660ff5fe41c61e7ae4db6828dc3f581e4d", size = 304638, upload-time = "2025-06-22T11:05:24.285Z" }, + { url = "https://files.pythonhosted.org/packages/73/9f/78d096ef795a813fa0e1cb9b33fa574b205f2b563d9c1e9366c854cf0364/pypdf-5.7.0-py3-none-any.whl", hash = "sha256:203379453439f5b68b7a1cd43cdf4c5f7a02b84810cefa7f93a47b350aaaba48", size = 305524, upload-time = "2025-06-29T08:49:46.16Z" }, ] [[package]] @@ -3057,11 +3073,11 @@ wheels = [ [[package]] name = "python-dotenv" -version = "1.1.0" +version = "1.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" }, + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, ] [[package]] @@ -3306,27 +3322,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/90/5255432602c0b196a0da6720f6f76b93eb50baef46d3c9b0025e2f9acbf3/ruff-0.12.0.tar.gz", hash = "sha256:4d047db3662418d4a848a3fdbfaf17488b34b62f527ed6f10cb8afd78135bc5c", size = 4376101, upload-time = "2025-06-17T15:19:26.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/fd/b46bb20e14b11ff49dbc74c61de352e0dc07fb650189513631f6fb5fc69f/ruff-0.12.0-py3-none-linux_armv6l.whl", hash = "sha256:5652a9ecdb308a1754d96a68827755f28d5dfb416b06f60fd9e13f26191a8848", size = 10311554, upload-time = "2025-06-17T15:18:45.792Z" }, - { url = "https://files.pythonhosted.org/packages/e7/d3/021dde5a988fa3e25d2468d1dadeea0ae89dc4bc67d0140c6e68818a12a1/ruff-0.12.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:05ed0c914fabc602fc1f3b42c53aa219e5736cb030cdd85640c32dbc73da74a6", size = 11118435, upload-time = "2025-06-17T15:18:49.064Z" }, - { url = "https://files.pythonhosted.org/packages/07/a2/01a5acf495265c667686ec418f19fd5c32bcc326d4c79ac28824aecd6a32/ruff-0.12.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:07a7aa9b69ac3fcfda3c507916d5d1bca10821fe3797d46bad10f2c6de1edda0", size = 10466010, upload-time = "2025-06-17T15:18:51.341Z" }, - { url = "https://files.pythonhosted.org/packages/4c/57/7caf31dd947d72e7aa06c60ecb19c135cad871a0a8a251723088132ce801/ruff-0.12.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7731c3eec50af71597243bace7ec6104616ca56dda2b99c89935fe926bdcd48", size = 10661366, upload-time = "2025-06-17T15:18:53.29Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ba/aa393b972a782b4bc9ea121e0e358a18981980856190d7d2b6187f63e03a/ruff-0.12.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:952d0630eae628250ab1c70a7fffb641b03e6b4a2d3f3ec6c1d19b4ab6c6c807", size = 10173492, upload-time = "2025-06-17T15:18:55.262Z" }, - { url = "https://files.pythonhosted.org/packages/d7/50/9349ee777614bc3062fc6b038503a59b2034d09dd259daf8192f56c06720/ruff-0.12.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c021f04ea06966b02614d442e94071781c424ab8e02ec7af2f037b4c1e01cc82", size = 11761739, upload-time = "2025-06-17T15:18:58.906Z" }, - { url = "https://files.pythonhosted.org/packages/04/8f/ad459de67c70ec112e2ba7206841c8f4eb340a03ee6a5cabc159fe558b8e/ruff-0.12.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d235618283718ee2fe14db07f954f9b2423700919dc688eacf3f8797a11315c", size = 12537098, upload-time = "2025-06-17T15:19:01.316Z" }, - { url = "https://files.pythonhosted.org/packages/ed/50/15ad9c80ebd3c4819f5bd8883e57329f538704ed57bac680d95cb6627527/ruff-0.12.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0758038f81beec8cc52ca22de9685b8ae7f7cc18c013ec2050012862cc9165", size = 12154122, upload-time = "2025-06-17T15:19:03.727Z" }, - { url = "https://files.pythonhosted.org/packages/76/e6/79b91e41bc8cc3e78ee95c87093c6cacfa275c786e53c9b11b9358026b3d/ruff-0.12.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:139b3d28027987b78fc8d6cfb61165447bdf3740e650b7c480744873688808c2", size = 11363374, upload-time = "2025-06-17T15:19:05.875Z" }, - { url = "https://files.pythonhosted.org/packages/db/c3/82b292ff8a561850934549aa9dc39e2c4e783ab3c21debe55a495ddf7827/ruff-0.12.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68853e8517b17bba004152aebd9dd77d5213e503a5f2789395b25f26acac0da4", size = 11587647, upload-time = "2025-06-17T15:19:08.246Z" }, - { url = "https://files.pythonhosted.org/packages/2b/42/d5760d742669f285909de1bbf50289baccb647b53e99b8a3b4f7ce1b2001/ruff-0.12.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3a9512af224b9ac4757f7010843771da6b2b0935a9e5e76bb407caa901a1a514", size = 10527284, upload-time = "2025-06-17T15:19:10.37Z" }, - { url = "https://files.pythonhosted.org/packages/19/f6/fcee9935f25a8a8bba4adbae62495c39ef281256693962c2159e8b284c5f/ruff-0.12.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b08df3d96db798e5beb488d4df03011874aff919a97dcc2dd8539bb2be5d6a88", size = 10158609, upload-time = "2025-06-17T15:19:12.286Z" }, - { url = "https://files.pythonhosted.org/packages/37/fb/057febf0eea07b9384787bfe197e8b3384aa05faa0d6bd844b94ceb29945/ruff-0.12.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a315992297a7435a66259073681bb0d8647a826b7a6de45c6934b2ca3a9ed51", size = 11141462, upload-time = "2025-06-17T15:19:15.195Z" }, - { url = "https://files.pythonhosted.org/packages/10/7c/1be8571011585914b9d23c95b15d07eec2d2303e94a03df58294bc9274d4/ruff-0.12.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e55e44e770e061f55a7dbc6e9aed47feea07731d809a3710feda2262d2d4d8a", size = 11641616, upload-time = "2025-06-17T15:19:17.6Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ef/b960ab4818f90ff59e571d03c3f992828d4683561095e80f9ef31f3d58b7/ruff-0.12.0-py3-none-win32.whl", hash = "sha256:7162a4c816f8d1555eb195c46ae0bd819834d2a3f18f98cc63819a7b46f474fb", size = 10525289, upload-time = "2025-06-17T15:19:19.688Z" }, - { url = "https://files.pythonhosted.org/packages/34/93/8b16034d493ef958a500f17cda3496c63a537ce9d5a6479feec9558f1695/ruff-0.12.0-py3-none-win_amd64.whl", hash = "sha256:d00b7a157b8fb6d3827b49d3324da34a1e3f93492c1f97b08e222ad7e9b291e0", size = 11598311, upload-time = "2025-06-17T15:19:21.785Z" }, - { url = "https://files.pythonhosted.org/packages/d0/33/4d3e79e4a84533d6cd526bfb42c020a23256ae5e4265d858bd1287831f7d/ruff-0.12.0-py3-none-win_arm64.whl", hash = "sha256:8cd24580405ad8c1cc64d61725bca091d6b6da7eb3d36f72cc605467069d7e8b", size = 10724946, upload-time = "2025-06-17T15:19:23.952Z" }, +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/97/38/796a101608a90494440856ccfb52b1edae90de0b817e76bfade66b12d320/ruff-0.12.1.tar.gz", hash = "sha256:806bbc17f1104fd57451a98a58df35388ee3ab422e029e8f5cf30aa4af2c138c", size = 4413426, upload-time = "2025-06-26T20:34:14.784Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/bf/3dba52c1d12ab5e78d75bd78ad52fb85a6a1f29cc447c2423037b82bed0d/ruff-0.12.1-py3-none-linux_armv6l.whl", hash = "sha256:6013a46d865111e2edb71ad692fbb8262e6c172587a57c0669332a449384a36b", size = 10305649, upload-time = "2025-06-26T20:33:39.242Z" }, + { url = "https://files.pythonhosted.org/packages/8c/65/dab1ba90269bc8c81ce1d499a6517e28fe6f87b2119ec449257d0983cceb/ruff-0.12.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b3f75a19e03a4b0757d1412edb7f27cffb0c700365e9d6b60bc1b68d35bc89e0", size = 11120201, upload-time = "2025-06-26T20:33:42.207Z" }, + { url = "https://files.pythonhosted.org/packages/3f/3e/2d819ffda01defe857fa2dd4cba4d19109713df4034cc36f06bbf582d62a/ruff-0.12.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9a256522893cb7e92bb1e1153283927f842dea2e48619c803243dccc8437b8be", size = 10466769, upload-time = "2025-06-26T20:33:44.102Z" }, + { url = "https://files.pythonhosted.org/packages/63/37/bde4cf84dbd7821c8de56ec4ccc2816bce8125684f7b9e22fe4ad92364de/ruff-0.12.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:069052605fe74c765a5b4272eb89880e0ff7a31e6c0dbf8767203c1fbd31c7ff", size = 10660902, upload-time = "2025-06-26T20:33:45.98Z" }, + { url = "https://files.pythonhosted.org/packages/0e/3a/390782a9ed1358c95e78ccc745eed1a9d657a537e5c4c4812fce06c8d1a0/ruff-0.12.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a684f125a4fec2d5a6501a466be3841113ba6847827be4573fddf8308b83477d", size = 10167002, upload-time = "2025-06-26T20:33:47.81Z" }, + { url = "https://files.pythonhosted.org/packages/6d/05/f2d4c965009634830e97ffe733201ec59e4addc5b1c0efa035645baa9e5f/ruff-0.12.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdecdef753bf1e95797593007569d8e1697a54fca843d78f6862f7dc279e23bd", size = 11751522, upload-time = "2025-06-26T20:33:49.857Z" }, + { url = "https://files.pythonhosted.org/packages/35/4e/4bfc519b5fcd462233f82fc20ef8b1e5ecce476c283b355af92c0935d5d9/ruff-0.12.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:70d52a058c0e7b88b602f575d23596e89bd7d8196437a4148381a3f73fcd5010", size = 12520264, upload-time = "2025-06-26T20:33:52.199Z" }, + { url = "https://files.pythonhosted.org/packages/85/b2/7756a6925da236b3a31f234b4167397c3e5f91edb861028a631546bad719/ruff-0.12.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84d0a69d1e8d716dfeab22d8d5e7c786b73f2106429a933cee51d7b09f861d4e", size = 12133882, upload-time = "2025-06-26T20:33:54.231Z" }, + { url = "https://files.pythonhosted.org/packages/dd/00/40da9c66d4a4d51291e619be6757fa65c91b92456ff4f01101593f3a1170/ruff-0.12.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cc32e863adcf9e71690248607ccdf25252eeeab5193768e6873b901fd441fed", size = 11608941, upload-time = "2025-06-26T20:33:56.202Z" }, + { url = "https://files.pythonhosted.org/packages/91/e7/f898391cc026a77fbe68dfea5940f8213622474cb848eb30215538a2dadf/ruff-0.12.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fd49a4619f90d5afc65cf42e07b6ae98bb454fd5029d03b306bd9e2273d44cc", size = 11602887, upload-time = "2025-06-26T20:33:58.47Z" }, + { url = "https://files.pythonhosted.org/packages/f6/02/0891872fc6aab8678084f4cf8826f85c5d2d24aa9114092139a38123f94b/ruff-0.12.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ed5af6aaaea20710e77698e2055b9ff9b3494891e1b24d26c07055459bb717e9", size = 10521742, upload-time = "2025-06-26T20:34:00.465Z" }, + { url = "https://files.pythonhosted.org/packages/2a/98/d6534322c74a7d47b0f33b036b2498ccac99d8d8c40edadb552c038cecf1/ruff-0.12.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:801d626de15e6bf988fbe7ce59b303a914ff9c616d5866f8c79eb5012720ae13", size = 10149909, upload-time = "2025-06-26T20:34:02.603Z" }, + { url = "https://files.pythonhosted.org/packages/34/5c/9b7ba8c19a31e2b6bd5e31aa1e65b533208a30512f118805371dbbbdf6a9/ruff-0.12.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2be9d32a147f98a1972c1e4df9a6956d612ca5f5578536814372113d09a27a6c", size = 11136005, upload-time = "2025-06-26T20:34:04.723Z" }, + { url = "https://files.pythonhosted.org/packages/dc/34/9bbefa4d0ff2c000e4e533f591499f6b834346025e11da97f4ded21cb23e/ruff-0.12.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:49b7ce354eed2a322fbaea80168c902de9504e6e174fd501e9447cad0232f9e6", size = 11648579, upload-time = "2025-06-26T20:34:06.766Z" }, + { url = "https://files.pythonhosted.org/packages/6f/1c/20cdb593783f8f411839ce749ec9ae9e4298c2b2079b40295c3e6e2089e1/ruff-0.12.1-py3-none-win32.whl", hash = "sha256:d973fa626d4c8267848755bd0414211a456e99e125dcab147f24daa9e991a245", size = 10519495, upload-time = "2025-06-26T20:34:08.718Z" }, + { url = "https://files.pythonhosted.org/packages/cf/56/7158bd8d3cf16394928f47c637d39a7d532268cd45220bdb6cd622985760/ruff-0.12.1-py3-none-win_amd64.whl", hash = "sha256:9e1123b1c033f77bd2590e4c1fe7e8ea72ef990a85d2484351d408224d603013", size = 11547485, upload-time = "2025-06-26T20:34:11.008Z" }, + { url = "https://files.pythonhosted.org/packages/91/d0/6902c0d017259439d6fd2fd9393cea1cfe30169940118b007d5e0ea7e954/ruff-0.12.1-py3-none-win_arm64.whl", hash = "sha256:78ad09a022c64c13cc6077707f036bab0fac8cd7088772dcd1e5be21c5002efc", size = 10691209, upload-time = "2025-06-26T20:34:12.928Z" }, ] [[package]] @@ -3506,7 +3522,7 @@ wheels = [ [[package]] name = "social-auth-core" -version = "4.6.1" +version = "4.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, @@ -3517,9 +3533,9 @@ dependencies = [ { name = "requests" }, { name = "requests-oauthlib" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/fc/9e11d4abb1c3cd78caf36ec7da76f8e3ccc1a1d9798f5f0e42de636cd37b/social_auth_core-4.6.1.tar.gz", hash = "sha256:563510844ccc043a727b120fe57726860c93158d4304fafa2c1e122f2deb4fd3", size = 228732, upload-time = "2025-04-28T07:23:48.759Z" } +sdist = { url = "https://files.pythonhosted.org/packages/87/c0/466383c22767604c573f15aff3ea2c37aacf3c10281f31199c02ac0017ef/social_auth_core-4.7.0.tar.gz", hash = "sha256:2bba127c7b7166a81085ddb0c248d93751b3bc3cdab8569f62d9f70c6bc4ed40", size = 230894, upload-time = "2025-06-27T06:34:27.15Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/a3/fbe5f146d41eae5ab017c211e617251841916d09001d60a380aaeea8f849/social_auth_core-4.6.1-py3-none-any.whl", hash = "sha256:1019fe2f7fe30f9ff7d15c04a32c15324ecdbd59f62fbe829031dab74071a21a", size = 424069, upload-time = "2025-04-28T07:23:47.083Z" }, + { url = "https://files.pythonhosted.org/packages/e3/3e/1b1ed868b840ecf5e7b02fc8ab20718ac24e184b90057815fee2ebbc107d/social_auth_core-4.7.0-py3-none-any.whl", hash = "sha256:9eef9b49c332d1a3265b37dcc698a7ace97c3fc59df2d874b51576d11d31f6a6", size = 427867, upload-time = "2025-06-27T06:34:25.715Z" }, ] [[package]] @@ -3872,11 +3888,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.2.3" +version = "2.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677, upload-time = "2024-09-12T10:52:18.401Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338, upload-time = "2024-09-12T10:52:16.589Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, ] [[package]]