Plain is headed towards 1.0! Subscribe for development updates →

  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