diff --git a/weblate/static/priorities/dash.svg b/weblate/static/priorities/dash.svg new file mode 100644 index 000000000000..a29f353bd87c --- /dev/null +++ b/weblate/static/priorities/dash.svg @@ -0,0 +1,7 @@ + + + + diff --git a/weblate/static/priorities/double_arrow_down.svg b/weblate/static/priorities/double_arrow_down.svg new file mode 100644 index 000000000000..099ef4a63d98 --- /dev/null +++ b/weblate/static/priorities/double_arrow_down.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/weblate/static/priorities/double_arrow_up.svg b/weblate/static/priorities/double_arrow_up.svg new file mode 100644 index 000000000000..f45dbac374b7 --- /dev/null +++ b/weblate/static/priorities/double_arrow_up.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/weblate/static/priorities/single_arrow_down.svg b/weblate/static/priorities/single_arrow_down.svg new file mode 100644 index 000000000000..de3d0ba54af2 --- /dev/null +++ b/weblate/static/priorities/single_arrow_down.svg @@ -0,0 +1,7 @@ + + + + diff --git a/weblate/static/priorities/single_arrow_up.svg b/weblate/static/priorities/single_arrow_up.svg new file mode 100644 index 000000000000..201f42133fdb --- /dev/null +++ b/weblate/static/priorities/single_arrow_up.svg @@ -0,0 +1,7 @@ + + + + diff --git a/weblate/trans/templatetags/translations.py b/weblate/trans/templatetags/translations.py index afdcff8e5037..d4fbbb264f68 100644 --- a/weblate/trans/templatetags/translations.py +++ b/weblate/trans/templatetags/translations.py @@ -47,6 +47,7 @@ from weblate.utils.docs import get_doc_url from weblate.utils.hash import hash_to_checksum from weblate.utils.html import format_html_join_comma, list_to_tuples +from weblate.utils.icons import load_icon from weblate.utils.markdown import render_markdown from weblate.utils.messages import get_message_kind as get_message_kind_impl from weblate.utils.random import get_random_identifier @@ -1221,6 +1222,35 @@ def indicate_alerts( # GhostProjectLanguageStats and GhostCategoryLanguageStats as these would # be confusing (showing alert or admin icon on ghost containers). + priority_html = "" + if component and (priority := getattr(component, "priority", None)) is not None: + levels = ( + (60, "double_arrow_up", "text-danger", gettext_lazy("Priority: Very high")), + (80, "single_arrow_up", "text-warning", gettext_lazy("Priority: High")), + (100, "dash", "text-info", gettext_lazy("Priority: Medium")), + (120, "single_arrow_down", "text-muted", gettext_lazy("Priority: Low")), + ) + + selected_svg = "double_arrow_down" + css_class = "text-secondary" + title_text = gettext_lazy("Priority: Very low") + for threshold, svg, css, title in levels: + if priority <= threshold: + selected_svg = svg + css_class = css + title_text = title + break + + priority_html = format_html( + '{}', + css_class, + title_text, + title_text, + mark_safe( # noqa: S308 + load_icon(f"priorities/{selected_svg}.svg", auto_prefix=False).decode() + ), + ) + icons = format_html_join( "\n", '{}{}{}', @@ -1256,7 +1286,7 @@ def indicate_alerts( component.license, ) - return format_html("{}{}", icons, license_badge) + return format_html("{}{}{}", priority_html, icons, license_badge) @register.filter(is_safe=True) diff --git a/weblate/trans/tests/test_templatetags.py b/weblate/trans/tests/test_templatetags.py index aaab1be30a8d..96f4340748cb 100644 --- a/weblate/trans/tests/test_templatetags.py +++ b/weblate/trans/tests/test_templatetags.py @@ -6,6 +6,9 @@ from __future__ import annotations +from unittest.mock import patch + +from django.template import Context from django.test import SimpleTestCase, TestCase from django.utils import timezone @@ -17,6 +20,7 @@ from weblate.trans.templatetags.translations import ( format_translation, get_location_links, + indicate_alerts, naturaltime, translation_progress_render, ) @@ -35,6 +39,50 @@ def test_natural(self) -> None: self.assertIn('class="naturaltime"', result) +class IndicateAlertsPriorityTest(SimpleTestCase): + def test_priority_icons(self) -> None: + project = Project(slug="p", name="p") + context = Context({}) + + cases = ( + (1, "double_arrow_up", "text-danger", 'title="Priority: Very high"'), + (60, "double_arrow_up", "text-danger", 'title="Priority: Very high"'), + (61, "single_arrow_up", "text-warning", 'title="Priority: High"'), + (80, "single_arrow_up", "text-warning", 'title="Priority: High"'), + (81, "dash", "text-info", 'title="Priority: Medium"'), + (100, "dash", "text-info", 'title="Priority: Medium"'), + (101, "single_arrow_down", "text-muted", 'title="Priority: Low"'), + (120, "single_arrow_down", "text-muted", 'title="Priority: Low"'), + (121, "double_arrow_down", "text-secondary", 'title="Priority: Very low"'), + (999, "double_arrow_down", "text-secondary", 'title="Priority: Very low"'), + ) + + def fake_load_icon(path: str, *, auto_prefix: bool = True) -> bytes: + return f''.encode() + + with ( + patch( + "weblate.trans.templatetags.translations.get_alerts", return_value=[] + ), + patch( + "weblate.trans.templatetags.translations.load_icon", + side_effect=fake_load_icon, + ), + ): + for priority, svg, css_class, title in cases: + component = Component( + project=project, + slug="c", + name="c", + priority=priority, + source_language=Language(), + ) + html = str(indicate_alerts(context, component)) + self.assertIn(f'data-icon="priorities/{svg}.svg"', html) + self.assertIn(f'class="state-icon {css_class}"', html) + self.assertIn(title, html) + + class LocationLinksTest(TestCase): def setUp(self) -> None: self.unit = Unit(