From c29e82141643adbb3f873a33cbe9f9f00cda9a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Horvat?= Date: Fri, 23 Feb 2024 12:41:30 +0100 Subject: [PATCH] Revert "Optimize logic to retrieve Resources in the Localization dashboard (#3107)" This reverts commit 0aa3811194da2926fa64f8669f4db54e90aa40cc. --- .../localizations/includes/resources.html | 12 +- .../localizations/widgets/resource_list.html | 4 +- pontoon/localizations/tests/test_views.py | 118 +++++++++++++----- pontoon/localizations/views.py | 93 +++++++++----- 4 files changed, 156 insertions(+), 71 deletions(-) diff --git a/pontoon/localizations/templates/localizations/includes/resources.html b/pontoon/localizations/templates/localizations/includes/resources.html index 038fe904dc..23237521e0 100644 --- a/pontoon/localizations/templates/localizations/includes/resources.html +++ b/pontoon/localizations/templates/localizations/includes/resources.html @@ -11,11 +11,13 @@ {{ ResourceList.header(deadline, priority) }} {% for resource in resources %} - {% set main_link = url('pontoon.translate', locale.code, project.slug, resource.title) %} - {% set chart_link = main_link %} - {% set latest_activity = resource.latest_activity %} - {% set chart = resource.chart %} - {{ ResourceList.item(resource, main_link, chart_link, latest_activity, chart, deadline, priority) }} + {% if not loop.last %} + {% set main_link = url('pontoon.translate', locale.code, project.slug, resource.title) %} + {% set chart_link = main_link %} + {% set latest_activity = resource.latest_activity %} + {% set chart = resource.chart %} + {{ ResourceList.item(resource, main_link, chart_link, latest_activity, chart, deadline, priority) }} + {% endif %} {% endfor %} {{ ResourceList.footer() }} diff --git a/pontoon/localizations/templates/localizations/widgets/resource_list.html b/pontoon/localizations/templates/localizations/widgets/resource_list.html index 867d19b219..a9b932c0d4 100644 --- a/pontoon/localizations/templates/localizations/widgets/resource_list.html +++ b/pontoon/localizations/templates/localizations/widgets/resource_list.html @@ -35,13 +35,13 @@

{% if deadline %} - {{ Deadline.deadline(resource.deadline, chart.completion_percent == 100) }} + {{ Deadline.deadline(resource.resource__deadline, chart.completion_percent == 100) }} {% endif %} {% if priority %} - {{ Priority.priority(resource.priority) }} + {{ Priority.priority(resource.resource__priority) }} {% endif %} diff --git a/pontoon/localizations/tests/test_views.py b/pontoon/localizations/tests/test_views.py index 9d65a30571..124ed97ca9 100644 --- a/pontoon/localizations/tests/test_views.py +++ b/pontoon/localizations/tests/test_views.py @@ -5,8 +5,8 @@ from django.urls import reverse from django.shortcuts import render +from pontoon.base.models import Locale from pontoon.base.tests import ( - EntityFactory, ResourceFactory, TranslationFactory, TranslatedResourceFactory, @@ -16,22 +16,44 @@ @pytest.mark.django_db @patch("pontoon.localizations.views.render", wraps=render) -def test_ajax_resources(mock_render, client, project_a, locale_a): +@patch.object(Locale, "parts_stats") +def test_latest_activity(mock_parts_stats, mock_render, client, project_a, locale_a): """Ensure that the latest_activity field is added to parts.""" ProjectLocaleFactory.create(locale=locale_a, project=project_a) - resource = ResourceFactory.create(project=project_a, path="has/stats.po") resource2 = ResourceFactory.create(project=project_a, path="has/stats2.po") - entity = EntityFactory.create(resource=resource) - EntityFactory.create(resource=resource2) - translation = TranslationFactory.create(entity=entity, locale=locale_a) - - tr = TranslatedResourceFactory.create( + translation = TranslationFactory.create(entity__resource=resource, locale=locale_a) + TranslatedResourceFactory.create( resource=resource2, locale=locale_a, latest_translation=translation ) - tr.total_strings = 1 - tr.save() + + mock_parts_stats.return_value = [ + { + "title": "has/stats.po", + "resource__path": "has/stats.po", + "resource__total_strings": 1, + "approved_strings": 0, + "unreviewed_strings": 1, + "pretranslated_strings": 0, + "strings_with_warnings": 0, + "strings_with_errors": 0, + "resource__deadline": None, + "resource__priority": None, + }, + { + "title": "no/stats.po", + "resource__path": "no/stats.po", + "resource__total_strings": 1, + "approved_strings": 0, + "unreviewed_strings": 0, + "pretranslated_strings": 0, + "strings_with_warnings": 0, + "strings_with_errors": 0, + "resource__deadline": None, + "resource__priority": None, + }, + ] client.get( reverse( @@ -43,23 +65,59 @@ def test_ajax_resources(mock_render, client, project_a, locale_a): ctx = mock_render.call_args[0][2] - assert len(ctx["resources"]) == 2 - - assert ctx["resources"][0].title == "has/stats2.po" - assert ctx["resources"][0].deadline is None - assert ctx["resources"][0].priority is None - assert ctx["resources"][0].latest_activity == translation.latest_activity - assert ctx["resources"][0].chart == { - "pretranslated_strings": 0, - "total_strings": 1, - "approved_strings": 0, - "unreviewed_strings": 0, - "strings_with_errors": 0, - "strings_with_warnings": 0, - "approved_share": 0.0, - "unreviewed_share": 0.0, - "pretranslated_share": 0.0, - "warnings_share": 0.0, - "errors_share": 0.0, - "completion_percent": 0, - } + assert ctx["resources"] == [ + { + "latest_activity": translation.latest_activity, + "title": "has/stats.po", + "resource__path": "has/stats.po", + "resource__deadline": None, + "resource__priority": None, + "resource__total_strings": 1, + "approved_strings": 0, + "unreviewed_strings": 1, + "pretranslated_strings": 0, + "strings_with_errors": 0, + "strings_with_warnings": 0, + "chart": { + "pretranslated_strings": 0, + "total_strings": 1, + "approved_strings": 0, + "unreviewed_strings": 1, + "strings_with_errors": 0, + "strings_with_warnings": 0, + "approved_share": 0.0, + "unreviewed_share": 100.0, + "pretranslated_share": 0.0, + "warnings_share": 0.0, + "errors_share": 0.0, + "completion_percent": 0, + }, + }, + { + "latest_activity": None, + "title": "no/stats.po", + "resource__path": "no/stats.po", + "resource__deadline": None, + "resource__priority": None, + "resource__total_strings": 1, + "approved_strings": 0, + "unreviewed_strings": 0, + "pretranslated_strings": 0, + "strings_with_errors": 0, + "strings_with_warnings": 0, + "chart": { + "pretranslated_strings": 0, + "total_strings": 1, + "approved_strings": 0, + "unreviewed_strings": 0, + "strings_with_errors": 0, + "strings_with_warnings": 0, + "approved_share": 0.0, + "unreviewed_share": 0.0, + "pretranslated_share": 0.0, + "warnings_share": 0.0, + "errors_share": 0.0, + "completion_percent": 0, + }, + }, + ] diff --git a/pontoon/localizations/views.py b/pontoon/localizations/views.py index 7cac191d88..4e92b25378 100644 --- a/pontoon/localizations/views.py +++ b/pontoon/localizations/views.py @@ -1,3 +1,4 @@ +import math from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.db.models import Q @@ -41,15 +42,7 @@ def localization(request, code, slug): project=project, ) - resource_count = ( - TranslatedResource.objects.filter( - resource__project=project, - locale=locale, - resource__entities__obsolete=False, - ) - .distinct() - .count() - ) + resource_count = len(locale.parts_stats(project)) - 1 return render( request, @@ -80,33 +73,65 @@ def ajax_resources(request, code, slug): # Check if ProjectLocale exists get_object_or_404(ProjectLocale, locale=locale, project=project) - # Prefetch data needed for the latest activity column - translatedresources = ( - TranslatedResource.objects.filter( - resource__project=project, - locale=locale, - resource__entities__obsolete=False, - ) - .order_by("resource__path") - .prefetch_related( - "resource", "latest_translation__user", "latest_translation__approved_user" - ) - .distinct() - ) + # Amend the parts dict with latest activity info. + translatedresources_qs = TranslatedResource.objects.filter( + resource__project=project, locale=locale + ).prefetch_related("resource", "latest_translation__user") - if not len(translatedresources): + if not len(translatedresources_qs): raise Http404 + translatedresources = {s.resource.path: s for s in translatedresources_qs} + translatedresources = dict(list(translatedresources.items())) + parts = locale.parts_stats(project) + resource_priority_map = project.resource_priority_map() - for tr in translatedresources: - tr.title = tr.resource.path - tr.deadline = tr.resource.deadline - tr.priority = resource_priority_map.get(tr.resource.path, None) - tr.latest_activity = ( - tr.latest_translation.latest_activity if tr.latest_translation else None - ) - tr.chart = TranslatedResource.get_chart_dict(tr) + for part in parts: + part["resource__priority"] = resource_priority_map.get(part["title"], None) + + translatedresource = translatedresources.get(part["title"], None) + if translatedresource and translatedresource.latest_translation: + part[ + "latest_activity" + ] = translatedresource.latest_translation.latest_activity + else: + part["latest_activity"] = None + + part["chart"] = { + "unreviewed_strings": part["unreviewed_strings"], + "pretranslated_strings": part["pretranslated_strings"], + "strings_with_errors": part["strings_with_errors"], + "strings_with_warnings": part["strings_with_warnings"], + "total_strings": part["resource__total_strings"], + "approved_strings": part["approved_strings"], + "approved_share": round( + part["approved_strings"] / part["resource__total_strings"] * 100 + ), + "unreviewed_share": round( + part["unreviewed_strings"] / part["resource__total_strings"] * 100 + ), + "pretranslated_share": round( + part["pretranslated_strings"] / part["resource__total_strings"] * 100 + ), + "errors_share": round( + part["strings_with_errors"] / part["resource__total_strings"] * 100 + ), + "warnings_share": round( + part["strings_with_warnings"] / part["resource__total_strings"] * 100 + ), + "completion_percent": int( + math.floor( + ( + part["approved_strings"] + + part["pretranslated_strings"] + + part["strings_with_warnings"] + ) + / part["resource__total_strings"] + * 100 + ) + ), + } return render( request, @@ -114,9 +139,9 @@ def ajax_resources(request, code, slug): { "locale": locale, "project": project, - "resources": translatedresources, - "deadline": any(tr.resource.deadline for tr in translatedresources), - "priority": any(tr.priority for tr in translatedresources), + "resources": parts, + "deadline": any(part["resource__deadline"] for part in parts), + "priority": any(part["resource__priority"] for part in parts), }, )