diff --git a/backend/projectify/lib/tests/test_views.py b/backend/projectify/lib/tests/test_views.py new file mode 100644 index 000000000..d71c5e91b --- /dev/null +++ b/backend/projectify/lib/tests/test_views.py @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +# +# SPDX-FileCopyrightText: 2026 JWP Consulting GK +"""Test lib views.""" + +from django.test.client import Client +from django.urls import reverse + +import pytest + + +class TestColoredIconView: + """Test the colored_icon view.""" + + def test_get(self, client: Client) -> None: + """Test getting an icon. Only test for one color.""" + url = reverse( + "colored-icon", + kwargs={"icon": "external_links", "color": "primary"}, + ) + response = client.get(url) + + assert response.status_code == 200 + assert response["Content-Type"] == "image/svg+xml" + assert ' None: + """Test that 404 is returned for invalid icon or color.""" + url = reverse( + "colored-icon", + kwargs={"icon": icon, "color": color}, + ) + assert client.get(url).status_code == 404 diff --git a/backend/projectify/lib/views.py b/backend/projectify/lib/views.py index 7574fbcee..b8f76cb59 100644 --- a/backend/projectify/lib/views.py +++ b/backend/projectify/lib/views.py @@ -1,15 +1,21 @@ # SPDX-License-Identifier: AGPL-3.0-or-later # -# SPDX-FileCopyrightText: 2024 JWP Consulting GK +# SPDX-FileCopyrightText: 2026 JWP Consulting GK """View decorators.""" +import logging +from pathlib import Path from typing import Any, Protocol from django.contrib.auth.decorators import login_required -from django.http import HttpResponse +from django.contrib.staticfiles import finders +from django.http import Http404, HttpRequest, HttpResponse +from django.views.decorators.cache import cache_control from projectify.lib.types import AuthenticatedHttpRequest +logger = logging.getLogger(__name__) + class LoggedInViewP(Protocol): """Django view method that takes an AuthenticatedHttpRequest.""" @@ -30,3 +36,35 @@ def platform_view(func: LoggedInViewP) -> LoggedInViewP: logged in. """ return login_required(func) + + +@cache_control(max_age=3600) +def colored_icon(request: HttpRequest, icon: str, color: str) -> HttpResponse: + """Return a colored SVG icon.""" + del request + # See `const colors` projectify/theme/static_src/tailwind.config.js + color_map = { + "primary": "#2563EB", + "destructive": "#dc2626", + "white": "#ffffff", + } + + match finders.find(f"heroicons/{icon}.svg"): + case list() as paths: + raise ValueError( + f"Tried to look for icon {icon}, got a list of paths {paths}" + ) + case None: + raise Http404(f"Icon '{icon}' not found") + case str() as icon_path: + pass + + if color not in color_map: + raise Http404(f"Missing color '{color}' for icon '{icon}'") + + svg_content = ( + Path(icon_path) + .read_text() + .replace(" {% csrf_token %} - {% include "onboarding/common/form_description.html" with title="About you" text_1="Tell us your preferred name. You can also keep it empty and continue by clicking the button below." %} -
-
{{ form }}
-
-
-
- -
-
+ {% include "onboarding/common/form_description.html" with title=_("About you") text_1=_("Tell us your preferred name. You can also keep it empty and continue by clicking the button below.") %} + {{ form }} + {% include "projectify/forms/submit.html" with text=_("Continue") %} + {% endblock onboarding_content %} diff --git a/backend/projectify/onboarding/templates/onboarding/assign_task.html b/backend/projectify/onboarding/templates/onboarding/assign_task.html index 6338cf190..969184502 100644 --- a/backend/projectify/onboarding/templates/onboarding/assign_task.html +++ b/backend/projectify/onboarding/templates/onboarding/assign_task.html @@ -2,6 +2,7 @@ {# SPDX-License-Identifier: AGPL-3.0-or-later #} {% extends "onboarding_base.html" %} {% load i18n %} +{% load projectify %} {% block title %} {% blocktrans %}Task "{{ task }}" has been assigned to you - Projectify{% endblocktrans %} {% endblock title %} @@ -13,34 +14,55 @@

{% blocktrans %}Task "{{task}}" has been assigned to you!{% endblocktrans %}

-

{% trans "You’re all set!" %}

+

{% trans "You're all set!" %}

{% trans "If you wish to add new team members to your workspace, please go to the workspace settings menu next to your workspace name." %}

- {% trans "Learn more about workspace billing settings" %}(Opens in new tab) - {% include "heroicons/external_links.svg" %} - - {# TODO:: Use django template url tag #} - {% trans "Go to workspace billing setting" %}(Opens in new tab) - {% include "heroicons/external_links.svg" %} - -
- -
-
{{ form }}
-
-
-
+ {% anchor href="help:detail" label=_("Learn more about workspace billing settings") external=True page="billing" %} + {% anchor href="dashboard:workspaces:billing" label=_("Go to workspace billing settings") external=True workspace_uuid=workspace.uuid %} +
+
{% trans "Get started" %} + {% include "onboarding/common/step_counter.html" with step=5 step_count="5" %} + + - -{% include "onboarding/common/step_counter.html" with step=5 step_count="5" %} - - {% endblock onboarding_content %} diff --git a/backend/projectify/onboarding/templates/onboarding/common/form_description.html b/backend/projectify/onboarding/templates/onboarding/common/form_description.html index c42b04070..8c99ac6f6 100644 --- a/backend/projectify/onboarding/templates/onboarding/common/form_description.html +++ b/backend/projectify/onboarding/templates/onboarding/common/form_description.html @@ -1,26 +1,16 @@ {# SPDX-FileCopyrightText: 2025 JWP Consulting GK #} {# SPDX-License-Identifier: AGPL-3.0-or-later #} {% load i18n %} +{% load projectify %}
-

{% trans title %}

+

{{ title }}

-

{% trans text_1 %}

- {% if text_2 %} -

{% trans text_2 %}

- {% endif %} +

{{ text_1 }}

+ {% if text_2 %}

{{ text_2 }}

{% endif %} {% if href %} - {% if target_blank %} - {% trans href_label %}{% trans "(Opens in new tab)" %} - {% include "heroicons/external_links.svg" %} - - {% else %} - {% trans href_label %} - {% endif %} - {% endif %} -
-
+

{% anchor href href_label external=target_blank %}

+ {% endif %} +
+ diff --git a/backend/projectify/onboarding/templates/onboarding/common/step_counter.html b/backend/projectify/onboarding/templates/onboarding/common/step_counter.html index 83bb6cded..9fbbc6ae3 100644 --- a/backend/projectify/onboarding/templates/onboarding/common/step_counter.html +++ b/backend/projectify/onboarding/templates/onboarding/common/step_counter.html @@ -4,7 +4,7 @@ {% with ''|center:step_count as range %} {% for _ in range %} {% if forloop.counter <= step %} -
  • +
  • {% else %}
  • {% endif %} diff --git a/backend/projectify/onboarding/templates/onboarding/new_label.html b/backend/projectify/onboarding/templates/onboarding/new_label.html index 122e18d80..d4e43db42 100644 --- a/backend/projectify/onboarding/templates/onboarding/new_label.html +++ b/backend/projectify/onboarding/templates/onboarding/new_label.html @@ -1,7 +1,8 @@ -{# SPDX-FileCopyrightText: 2025 JWP Consulting GK #} +{# SPDX-FileCopyrightText: 2025-2026 JWP Consulting GK #} {# SPDX-License-Identifier: AGPL-3.0-or-later #} {% extends "onboarding_base.html" %} {% load i18n %} +{% load projectify %} {% block title %} {% blocktrans %}Create a label for "{{ task }}" - Projectify{% endblocktrans %} {% endblock title %} @@ -10,24 +11,67 @@ class="col-span-1 flex shrink grow flex-col gap-16 px-12 py-20 pb-8"> {% csrf_token %}
    -

    {% blocktrans %}Create a label for "{{task}}"{% endblocktrans %}

    -
    -

    {% trans "Labels help you to filter between the types of tasks." %}

    -
    -
    -
    -
    {{ form }}
    -
    -
    -
    - -
    +

    + {% blocktrans %}Create a label for "{{task}}"{% endblocktrans %} +

    +

    {% trans "Labels help you to filter between the types of tasks." %}

    + {{ form }} + {% include "projectify/forms/submit.html" with text=_("Continue") %} {% include "onboarding/common/step_counter.html" with step=4 step_count="5" %} - -
    -
    {{ form }}
    -
    -
    -
    - + {{ form }} + {% include "projectify/forms/submit.html" with text=_("Continue") %} + {% include "onboarding/common/step_counter.html" with step=2 step_count=5 %} + +