From 9bb5656d4074fed927ceb05cec626b07cddac323 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C4=93teris=20Caune?= <cuu508@gmail.com>
Date: Wed, 10 Apr 2024 14:36:42 +0300
Subject: [PATCH] Implement dynamic favicon in the projects overview page

cc: #971
---
 CHANGELOG.md                  | 1 +
 hc/front/tests/test_index.py  | 2 ++
 hc/front/views.py             | 4 ++++
 static/js/projects.js         | 5 +++++
 templates/front/projects.html | 7 +++++++
 5 files changed, 19 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9cac572d..39cfc184 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
 
 ### Improvements
 - Show status changes (flips) in check's log page (#447)
+- Implement dynamic favicon in the projects overview page (#971)
 
 ## v3.3 - 2024-04-03
 
diff --git a/hc/front/tests/test_index.py b/hc/front/tests/test_index.py
index 8fc4e308..d31fa45d 100644
--- a/hc/front/tests/test_index.py
+++ b/hc/front/tests/test_index.py
@@ -18,6 +18,7 @@ class IndexTestCase(BaseTestCase):
         self.assertContains(r, "Alices Project")
         self.assertContains(r, "3 checks")
         self.assertContains(r, "status ic-up")
+        self.assertContains(r, "favicon.svg")
 
     def test_it_shows_overall_down_status(self) -> None:
         self.c1.status = "down"
@@ -26,3 +27,4 @@ class IndexTestCase(BaseTestCase):
         self.client.login(username="alice@example.org", password="password")
         r = self.client.get("/")
         self.assertContains(r, "status ic-down")
+        self.assertContains(r, "favicon_down.svg")
diff --git a/hc/front/views.py b/hc/front/views.py
index 62504e34..88688918 100644
--- a/hc/front/views.py
+++ b/hc/front/views.py
@@ -373,9 +373,12 @@ def index(request: HttpRequest) -> HttpResponse:
     q = q.annotate(n_channels=Count("channel", distinct=True))
     q = q.annotate(owner_email=F("owner__email"))
     projects = list(q)
+    any_down = False
     for project in projects:
         setattr(project, "overall_status", summary[project.code]["status"])
         setattr(project, "any_started", summary[project.code]["started"])
+        if summary[project.code]["status"] == "down":
+            any_down = True
 
     # The list returned by projects() is already sorted . Do an additional sorting pass
     # to move projects with overall_status=down to the front (without changing their
@@ -386,6 +389,7 @@ def index(request: HttpRequest) -> HttpResponse:
         "page": "projects",
         "projects": projects,
         "last_project_id": request.session.get("last_project_id"),
+        "any_down": any_down,
     }
 
     return render(request, "front/projects.html", ctx)
diff --git a/static/js/projects.js b/static/js/projects.js
index 0a1c129d..f4141742 100644
--- a/static/js/projects.js
+++ b/static/js/projects.js
@@ -1,5 +1,6 @@
 $(function () {
     var base = document.getElementById("base-url").getAttribute("href").slice(0, -1);
+    var favicon = document.querySelector('link[rel="icon"]');
 
     // Schedule refresh to run every 3s when tab is visible and user
     // is active, every 60s otherwise
@@ -11,8 +12,10 @@ $(function () {
             dataType: "json",
             timeout: 2000,
             success: function(data) {
+                var anyDown = false;
                 for (var code in data) {
                     var el = data[code];
+                    anyDown = anyDown || (el.status == "down");
 
                     if (el.status != lastStatus[code]) {
                         $("#" + code + " div.status").attr("class", "status ic-" + el.status);
@@ -24,6 +27,8 @@ $(function () {
                         lastStarted[code] = el.started;
                     }
                 }
+                var downPostfix = anyDown ? "_down" : "";
+                favicon.href = `${base}/static/img/favicon${downPostfix}.svg`;
             }
         });
     }
diff --git a/templates/front/projects.html b/templates/front/projects.html
index cbee6719..f6c51ab8 100644
--- a/templates/front/projects.html
+++ b/templates/front/projects.html
@@ -2,6 +2,13 @@
 {% load compress static hc_extras %}
 
 {% block title %}{{ site_name }}{% endblock %}
+{% block favicon %}
+    {% if any_down %}
+    <link rel="icon" type="image/svg+xml" href="{% static 'img/favicon_down.svg' %}">
+    {% else %}
+    <link rel="icon" type="image/svg+xml" href="{% static 'img/favicon.svg' %}">
+    {% endif %}
+{% endblock %}
 
 
 {% block content %}