feat(core): add layered side rail preferences
This commit is contained in:
@@ -5301,6 +5301,12 @@ class ApiSmokeTests(unittest.TestCase):
|
||||
"allow_tenant_api_keys": system_item["allow_tenant_api_keys"],
|
||||
"available_languages": available_languages,
|
||||
"enabled_language_codes": enabled_codes,
|
||||
"navigation": {
|
||||
"contract_version": "1",
|
||||
"order": ["mail.navigation.mail", "files.navigation.files"],
|
||||
"hidden": [],
|
||||
"locked": ["mail.navigation.mail"],
|
||||
},
|
||||
},
|
||||
)
|
||||
self.assertEqual(updated_system.status_code, 200, updated_system.text)
|
||||
@@ -5314,7 +5320,29 @@ class ApiSmokeTests(unittest.TestCase):
|
||||
system_delta_payload = system_delta.json()
|
||||
self.assertFalse(system_delta_payload["full"])
|
||||
self.assertIn("languages", system_delta_payload["changed_sections"])
|
||||
self.assertIn("navigation", system_delta_payload["changed_sections"])
|
||||
self.assertIn("fr", system_delta_payload["sections"]["languages"]["enabled_language_codes"])
|
||||
self.assertEqual(
|
||||
["mail.navigation.mail"],
|
||||
system_delta_payload["sections"]["navigation"]["locked"],
|
||||
)
|
||||
|
||||
tenant_item = tenant_initial_payload["item"]
|
||||
updated_tenant = self.client.patch(
|
||||
"/api/v1/admin/tenant/settings",
|
||||
headers=headers,
|
||||
json={
|
||||
"default_locale": tenant_item["default_locale"],
|
||||
"enabled_language_codes": tenant_item["enabled_language_codes"],
|
||||
"navigation": {
|
||||
"contract_version": "1",
|
||||
"order": ["files.navigation.files"],
|
||||
"hidden": ["files.navigation.files"],
|
||||
"locked": [],
|
||||
},
|
||||
},
|
||||
)
|
||||
self.assertEqual(updated_tenant.status_code, 200, updated_tenant.text)
|
||||
|
||||
tenant_delta = self.client.get(
|
||||
"/api/v1/admin/tenant/settings/delta",
|
||||
@@ -5325,7 +5353,12 @@ class ApiSmokeTests(unittest.TestCase):
|
||||
tenant_delta_payload = tenant_delta.json()
|
||||
self.assertFalse(tenant_delta_payload["full"])
|
||||
self.assertIn("languages", tenant_delta_payload["changed_sections"])
|
||||
self.assertIn("navigation", tenant_delta_payload["changed_sections"])
|
||||
self.assertIn("fr", tenant_delta_payload["sections"]["languages"]["system_enabled_language_codes"])
|
||||
self.assertEqual(
|
||||
["files.navigation.files"],
|
||||
tenant_delta_payload["sections"]["navigation"]["hidden"],
|
||||
)
|
||||
|
||||
def test_tenant_admin_delta_tracks_create_and_update(self) -> None:
|
||||
headers, _ = self._login()
|
||||
@@ -6431,6 +6464,11 @@ class ApiSmokeTests(unittest.TestCase):
|
||||
"reduce_motion": True,
|
||||
"sticky_section_sidebars": False,
|
||||
"theme": "dark",
|
||||
"navigation": {
|
||||
"contract_version": "1",
|
||||
"order": ["files.navigation.files", "mail.navigation.mail"],
|
||||
"hidden": ["mail.navigation.mail"],
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -6445,8 +6483,30 @@ class ApiSmokeTests(unittest.TestCase):
|
||||
"reduce_motion": True,
|
||||
"sticky_section_sidebars": False,
|
||||
"theme": "dark",
|
||||
"navigation": {
|
||||
"contract_version": "1",
|
||||
"order": ["files.navigation.files", "mail.navigation.mail"],
|
||||
"hidden": ["mail.navigation.mail"],
|
||||
"locked": [],
|
||||
},
|
||||
},
|
||||
)
|
||||
rejected_lock = self.client.patch(
|
||||
"/api/v1/auth/profile",
|
||||
headers=headers,
|
||||
json={
|
||||
"ui_preferences": {
|
||||
**profile.json()["user"]["ui_preferences"],
|
||||
"navigation": {
|
||||
"contract_version": "1",
|
||||
"order": [],
|
||||
"hidden": [],
|
||||
"locked": ["files.navigation.files"],
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
self.assertEqual(rejected_lock.status_code, 422, rejected_lock.text)
|
||||
refreshed = self.client.get("/api/v1/auth/me", headers=headers)
|
||||
self.assertEqual(refreshed.status_code, 200, refreshed.text)
|
||||
self.assertEqual(refreshed.json()["user"]["display_name"], "Global Account Name")
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from govoplan_core.core.navigation import (
|
||||
NavigationPreferences,
|
||||
navigation_preferences_from_settings,
|
||||
resolve_navigation_preferences,
|
||||
update_navigation_preferences,
|
||||
)
|
||||
|
||||
|
||||
class NavigationPreferenceTests(unittest.TestCase):
|
||||
def test_user_order_overrides_tenant_and_system_order(self) -> None:
|
||||
resolved = resolve_navigation_preferences(
|
||||
("dashboard", "files", "mail", "campaign"),
|
||||
system=NavigationPreferences(order=("mail", "files")),
|
||||
tenant=NavigationPreferences(order=("campaign", "mail")),
|
||||
user=NavigationPreferences(order=("files", "campaign")),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
["files", "campaign", "mail", "dashboard"],
|
||||
[item.id for item in sorted(resolved.values(), key=lambda item: item.order)],
|
||||
)
|
||||
self.assertEqual("user", resolved["files"].order_source)
|
||||
self.assertEqual("user", resolved["campaign"].order_source)
|
||||
|
||||
def test_lower_scope_cannot_hide_locked_item(self) -> None:
|
||||
resolved = resolve_navigation_preferences(
|
||||
("dashboard", "files", "mail"),
|
||||
system=NavigationPreferences(locked=("dashboard",)),
|
||||
tenant=NavigationPreferences(hidden=("dashboard", "files"), locked=("mail",)),
|
||||
user=NavigationPreferences(hidden=("dashboard", "mail")),
|
||||
)
|
||||
|
||||
self.assertTrue(resolved["dashboard"].visible)
|
||||
self.assertTrue(resolved["dashboard"].locked)
|
||||
self.assertEqual("system", resolved["dashboard"].lock_source)
|
||||
self.assertTrue(resolved["mail"].visible)
|
||||
self.assertEqual("tenant", resolved["mail"].lock_source)
|
||||
self.assertTrue(resolved["files"].visible)
|
||||
self.assertEqual("user", resolved["files"].visibility_source)
|
||||
|
||||
def test_higher_scope_visibility_replaces_inherited_preference(self) -> None:
|
||||
resolved = resolve_navigation_preferences(
|
||||
("files", "mail"),
|
||||
system=NavigationPreferences(hidden=("mail",)),
|
||||
tenant=NavigationPreferences(hidden=("files",)),
|
||||
)
|
||||
|
||||
self.assertTrue(resolved["mail"].visible)
|
||||
self.assertFalse(resolved["files"].visible)
|
||||
self.assertEqual("tenant", resolved["mail"].visibility_source)
|
||||
|
||||
def test_settings_round_trip_is_bounded_and_normalized(self) -> None:
|
||||
settings = update_navigation_preferences(
|
||||
{"unrelated": {"preserved": True}},
|
||||
NavigationPreferences(order=(" files ", "files", "mail"), hidden=("mail",)),
|
||||
)
|
||||
parsed = navigation_preferences_from_settings(settings)
|
||||
|
||||
self.assertEqual(("files", "mail"), parsed.order if parsed else ())
|
||||
self.assertEqual(("mail",), parsed.hidden if parsed else ())
|
||||
self.assertEqual({"preserved": True}, settings["unrelated"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user