1from plain.urls import path, reverse_lazy
2
3
4class StaffViewRegistry:
5 def __init__(self):
6 # View classes that will be added to the admin automatically
7 self.registered_views = set()
8 self.registered_dashboards = set()
9
10 def register_view(self, view=None):
11 def inner(view):
12 self.registered_views.add(view)
13 # TODO do this somewhere else...
14 # self.registered_views = set(self.registered_views, key=lambda v: v.title)
15 return view
16
17 if callable(view):
18 return inner(view)
19 else:
20 return inner
21
22 def register_dashboard(self, view=None):
23 def inner(view):
24 self.registered_dashboards.add(view)
25 return view
26
27 if callable(view):
28 return inner(view)
29 else:
30 return inner
31
32 def register_viewset(self, viewset=None):
33 def inner(viewset):
34 for view in viewset.get_views():
35 self.register_view(view)
36 return viewset
37
38 if callable(viewset):
39 return inner(viewset)
40 else:
41 return inner
42
43 def get_nav_sections(self):
44 # class NavItem:
45 # def __init__(self, view, children):
46 # self.view = view
47 # self.children = children
48
49 sections = {}
50
51 for view in self.registered_views:
52 section = view.get_nav_section()
53 if not section:
54 continue
55 if section not in sections:
56 sections[section] = []
57 sections[section].append(view)
58
59 # Sort each section by title
60 for section in sections.values():
61 section.sort(key=lambda v: v.get_title())
62
63 # Sort sections dictionary by key
64 sections = dict(sorted(sections.items()))
65
66 return sections
67
68 # root_nav_items = []
69
70 # for view in sorted_views:
71 # if view.parent_view_class:
72 # continue
73 # children = [x for x in sorted_views if x.parent_view_class == view]
74 # root_nav_items.append(NavItem(view, children))
75
76 # return root_nav_items
77
78 def get_urls(self):
79 urlpatterns = []
80
81 paths_seen = set()
82
83 def add_view_path(view, _path):
84 if _path in paths_seen:
85 raise ValueError(f"Path {_path} already registered")
86 paths_seen.add(_path)
87 if not _path.endswith("/"):
88 _path += "/"
89 urlpatterns.append(path(_path, view, name=view.view_name()))
90
91 for view in self.registered_views:
92 add_view_path(view, f"p/{view.get_path()}")
93
94 for view in self.registered_dashboards:
95 add_view_path(view, f"dashboards/{view.get_path()}")
96
97 return urlpatterns
98
99 def get_searchable_views(self):
100 views = [
101 view
102 for view in self.registered_views
103 if getattr(view, "allow_global_search", False)
104 ]
105 views.sort(key=lambda v: v.get_title())
106 return views
107
108 def get_model_detail_url(self, instance):
109 from plain.staff.views.base import URL_NAMESPACE
110 from plain.staff.views.models import StaffModelDetailView
111
112 if not instance.pk:
113 # Has to actually be in the db
114 return
115
116 for view in self.registered_views:
117 if not issubclass(view, StaffModelDetailView):
118 continue
119
120 if view.model == instance.__class__:
121 return reverse_lazy(
122 f"{URL_NAMESPACE}:{view.view_name()}",
123 kwargs={"pk": instance.pk},
124 )
125
126
127registry = StaffViewRegistry()
128register_view = registry.register_view
129register_dashboard = registry.register_dashboard
130register_viewset = registry.register_viewset
131get_model_detail_url = registry.get_model_detail_url