Repository: zulip/zulip

Issue:
Make sure we're showing flutter app correctly in /stats graphs and the like
The discussion in https://github.com/zulip/zulip-flutter/issues/453 reminded me that we should audit the codebase for where we check for `ZulipMobile` use and make sure all of that code works well with the Flutter app. Most significant is likely to be figuring out how we want to display it on the /stats graphs.


Discussion:
Hello @zulip/server-analytics members, this issue was labeled with the "area: analytics" label, so you may want to check it out!

<!-- areaLabelAddition -->


Resolving patch:
diff --git a/analytics/management/commands/populate_analytics_db.py b/analytics/management/commands/populate_analytics_db.py
--- a/analytics/management/commands/populate_analytics_db.py
+++ b/analytics/management/commands/populate_analytics_db.py
@@ -285,6 +285,7 @@ def insert_fixture_data(
         android, created = Client.objects.get_or_create(name="ZulipAndroid")
         iOS, created = Client.objects.get_or_create(name="ZulipiOS")
         react_native, created = Client.objects.get_or_create(name="ZulipMobile")
+        flutter, created = Client.objects.get_or_create(name="ZulipFlutter")
         API, created = Client.objects.get_or_create(name="API: Python")
         zephyr_mirror, created = Client.objects.get_or_create(name="zephyr_mirror")
         unused, created = Client.objects.get_or_create(name="unused")
@@ -302,6 +303,7 @@ def insert_fixture_data(
             android.id: self.generate_fixture_data(stat, 5, 5, 2, 0.6, 3),
             iOS.id: self.generate_fixture_data(stat, 5, 5, 2, 0.6, 3),
             react_native.id: self.generate_fixture_data(stat, 5, 5, 10, 0.6, 3),
+            flutter.id: self.generate_fixture_data(stat, 5, 5, 10, 0.6, 3),
             API.id: self.generate_fixture_data(stat, 5, 5, 5, 0.6, 3),
             zephyr_mirror.id: self.generate_fixture_data(stat, 1, 1, 3, 0.6, 3),
             unused.id: self.generate_fixture_data(stat, 0, 0, 0, 0, 0),
@@ -313,6 +315,7 @@ def insert_fixture_data(
             old_desktop.id: self.generate_fixture_data(stat, 50, 30, 8, 0.6, 3),
             android.id: self.generate_fixture_data(stat, 50, 50, 2, 0.6, 3),
             iOS.id: self.generate_fixture_data(stat, 50, 50, 2, 0.6, 3),
+            flutter.id: self.generate_fixture_data(stat, 5, 5, 10, 0.6, 3),
             react_native.id: self.generate_fixture_data(stat, 5, 5, 10, 0.6, 3),
             API.id: self.generate_fixture_data(stat, 50, 50, 5, 0.6, 3),
             zephyr_mirror.id: self.generate_fixture_data(stat, 10, 10, 3, 0.6, 3),
diff --git a/analytics/views/stats.py b/analytics/views/stats.py
--- a/analytics/views/stats.py
+++ b/analytics/views/stats.py
@@ -525,7 +525,9 @@ def client_label_map(name: str) -> str:
     if name == "ZulipiOS":
         return "Old iOS app"
     if name == "ZulipMobile":
-        return "Mobile app"
+        return "Mobile app (React Native)"
+    if name in ["ZulipFlutter", "ZulipMobile/flutter"]:
+        return "Mobile app beta (Flutter)"
     if name in ["ZulipPython", "API: Python"]:
         return "Python API"
     if name.startswith("Zulip") and name.endswith("Webhook"):


Test patch:
diff --git a/analytics/tests/test_stats_views.py b/analytics/tests/test_stats_views.py
--- a/analytics/tests/test_stats_views.py
+++ b/analytics/tests/test_stats_views.py
@@ -661,7 +661,9 @@ def test_map_arrays(self) -> None:
             "website": [1, 2, 3],
             "ZulipiOS": [1, 2, 3],
             "ZulipElectron": [2, 5, 7],
-            "ZulipMobile": [1, 5, 7],
+            "ZulipMobile": [1, 2, 3],
+            "ZulipMobile/flutter": [1, 1, 1],
+            "ZulipFlutter": [1, 1, 1],
             "ZulipPython": [1, 2, 3],
             "API: Python": [1, 2, 3],
             "SomethingRandom": [4, 5, 6],
@@ -676,7 +678,8 @@ def test_map_arrays(self) -> None:
                 "Old desktop app": [32, 36, 39],
                 "Old iOS app": [1, 2, 3],
                 "Desktop app": [2, 5, 7],
-                "Mobile app": [1, 5, 7],
+                "Mobile app (React Native)": [1, 2, 3],
+                "Mobile app beta (Flutter)": [2, 2, 2],
                 "Web app": [1, 2, 3],
                 "Python API": [2, 4, 6],
                 "SomethingRandom": [4, 5, 6],