From 9d2bcff96bcb9d71250af55ebace4e50b81132ad Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 14 Jan 2023 18:48:56 -0600 Subject: [PATCH] Add full set of default menus plus dynamic set of integration menus, from providers --- tailbone/handler.py | 9 ++ tailbone/menus.py | 350 ++++++++++++++++++++++++++++++------------ tailbone/providers.py | 5 +- 3 files changed, 269 insertions(+), 95 deletions(-) diff --git a/tailbone/handler.py b/tailbone/handler.py index c665545a..cb78dc82 100644 --- a/tailbone/handler.py +++ b/tailbone/handler.py @@ -26,8 +26,12 @@ Tailbone Handler from __future__ import unicode_literals, absolute_import +import six + from rattail.app import GenericHandler +from tailbone.providers import get_all_providers + class TailboneHandler(GenericHandler): """ @@ -46,4 +50,9 @@ class TailboneHandler(GenericHandler): default='tailbone.menus:MenuHandler') Handler = self.app.load_object(spec) self.menu_handler = Handler(self.config) + self.menu_handler.tb = self return self.menu_handler + + def iter_providers(self): + providers = get_all_providers(self.config) + return six.itervalues(providers) diff --git a/tailbone/menus.py b/tailbone/menus.py index d3a2a4aa..a9de79dc 100644 --- a/tailbone/menus.py +++ b/tailbone/menus.py @@ -258,107 +258,269 @@ class MenuHandler(GenericHandler): This method provides a semi-sane menu set by default, but it is expected for most apps to override it. """ - return [ - self.make_admin_menu(request), + menus = [ + self.make_people_menu(request), + self.make_products_menu(request), + self.make_vendors_menu(request), ] - def make_admin_menu(self, request, include_stores=False, **kwargs): + integration_menus = self.make_integration_menus(request) + if integration_menus: + menus.extend(integration_menus) + + menus.extend([ + # TODO: add reporting menu + self.make_batches_menu(request), + self.make_admin_menu(request), + ]) + + return menus + + def make_integration_menus(self, request, **kwargs): + """ + Make a set of menus for all registered system integrations. + """ + menus = [] + for provider in self.tb.iter_providers(): + menu = provider.make_integration_menu(request) + if menu: + menus.append(menu) + menus.sort(key=lambda menu: menu['title'].lower()) + return menus + + def make_people_menu(self, request, **kwargs): + """ + Generate a typical People menu + """ + return { + 'title': "People", + 'type': 'menu', + 'items': [ + { + 'title': "Members", + 'route': 'members', + 'perm': 'members.list', + }, + { + 'title': "Customers", + 'route': 'customers', + 'perm': 'customers.list', + }, + { + 'title': "Customer Groups", + 'route': 'customergroups', + 'perm': 'customergroups.list', + }, + { + 'title': "Employees", + 'route': 'employees', + 'perm': 'employees.list', + }, + { + 'title': "All People", + 'route': 'people', + 'perm': 'people.list', + }, + ], + } + + def make_products_menu(self, request, **kwargs): + """ + Generate a typical Products menu + """ + return { + 'title': "Products", + 'type': 'menu', + 'items': [ + { + 'title': "Products", + 'route': 'products', + 'perm': 'products.list', + }, + { + 'title': "Departments", + 'route': 'departments', + 'perm': 'departments.list', + }, + { + 'title': "Subdepartments", + 'route': 'subdepartments', + 'perm': 'subdepartments.list', + }, + { + 'title': "Brands", + 'route': 'brands', + 'perm': 'brands.list', + }, + { + 'title': "Families", + 'route': 'families', + 'perm': 'families.list', + }, + { + 'title': "Report Codes", + 'route': 'reportcodes', + 'perm': 'reportcodes.list', + }, + ], + } + + def make_vendors_menu(self, request, **kwargs): + """ + Generate a typical Vendors menu + """ + return { + 'title': "Vendors", + 'type': 'menu', + 'items': [ + { + 'title': "Vendors", + 'route': 'vendors', + 'perm': 'vendors.list', + }, + {'type': 'sep'}, + { + 'title': "Ordering", + 'route': 'ordering', + 'perm': 'ordering.list', + }, + { + 'title': "Receiving", + 'route': 'receiving', + 'perm': 'receiving.list', + }, + {'type': 'sep'}, + { + 'title': "Purchases", + 'route': 'purchases', + 'perm': 'purchases.list', + }, + { + 'title': "Credits", + 'route': 'purchases.credits', + 'perm': 'purchases.credits.list', + }, + # {'type': 'sep'}, + # { + # 'title': "Catalogs", + # 'route': 'vendorcatalogs', + # 'perm': 'vendorcatalogs.list', + # }, + ], + } + + def make_batches_menu(self, request, **kwargs): + """ + Generate a typical Batches menu + """ + return { + 'title': "Batches", + 'type': 'menu', + 'items': [ + { + 'title': "Handheld", + 'route': 'batch.handheld', + 'perm': 'batch.handheld.list', + }, + # { + # 'title': "Inventory", + # 'route': 'batch.inventory', + # 'perm': 'batch.inventory.list', + # }, + ], + } + + def make_admin_menu(self, request, **kwargs): """ Generate a typical Admin menu """ - items = [] - - if include_stores: - items.append({ - 'title': "Stores", - 'route': 'stores', - 'perm': 'stores.list', - }) - - items.extend([ - { - 'title': "Users", - 'route': 'users', - 'perm': 'users.list', - }, - { - 'title': "User Events", - 'route': 'userevents', - 'perm': 'userevents.list', - }, - { - 'title': "Roles", - 'route': 'roles', - 'perm': 'roles.list', - }, - {'type': 'sep'}, - { - 'title': "App Settings", - 'route': 'appsettings', - 'perm': 'settings.list', - }, - { - 'title': "Email Settings", - 'route': 'emailprofiles', - 'perm': 'emailprofiles.list', - }, - { - 'title': "Email Attempts", - 'route': 'email_attempts', - 'perm': 'email_attempts.list', - }, - { - 'title': "Raw Settings", - 'route': 'settings', - 'perm': 'settings.list', - }, - {'type': 'sep'}, - { - 'title': "DataSync Changes", - 'route': 'datasyncchanges', - 'perm': 'datasync_changes.list', - }, - { - 'title': "DataSync Status", - 'route': 'datasync.status', - 'perm': 'datasync.status', - }, - { - 'title': "Importing / Exporting", - 'route': 'importing', - 'perm': 'importing.list', - }, - { - 'title': "Luigi Tasks", - 'route': 'luigi', - 'perm': 'luigi.list', - }, - { - 'title': "Tables", - 'route': 'tables', - 'perm': 'tables.list', - }, - { - 'title': "App Info", - 'route': 'appinfo', - 'perm': 'appinfo.list', - }, - { - 'title': "Configure App", - 'route': 'appinfo.configure', - 'perm': 'appinfo.configure', - }, - { - 'title': "Upgrades", - 'route': 'upgrades', - 'perm': 'upgrades.list', - }, - ]) - return { 'title': "Admin", 'type': 'menu', - 'items': items, + 'items': [ + { + 'title': "Stores", + 'route': 'stores', + 'perm': 'stores.list', + }, + { + 'title': "Users", + 'route': 'users', + 'perm': 'users.list', + }, + { + 'title': "User Events", + 'route': 'userevents', + 'perm': 'userevents.list', + }, + { + 'title': "Roles", + 'route': 'roles', + 'perm': 'roles.list', + }, + {'type': 'sep'}, + { + 'title': "App Settings", + 'route': 'appsettings', + 'perm': 'settings.list', + }, + { + 'title': "Email Settings", + 'route': 'emailprofiles', + 'perm': 'emailprofiles.list', + }, + { + 'title': "Email Attempts", + 'route': 'email_attempts', + 'perm': 'email_attempts.list', + }, + { + 'title': "Raw Settings", + 'route': 'settings', + 'perm': 'settings.list', + }, + {'type': 'sep'}, + { + 'title': "DataSync Changes", + 'route': 'datasyncchanges', + 'perm': 'datasync_changes.list', + }, + { + 'title': "DataSync Status", + 'route': 'datasync.status', + 'perm': 'datasync.status', + }, + { + 'title': "Importing / Exporting", + 'route': 'importing', + 'perm': 'importing.list', + }, + { + 'title': "Luigi Tasks", + 'route': 'luigi', + 'perm': 'luigi.list', + }, + { + 'title': "Tables", + 'route': 'tables', + 'perm': 'tables.list', + }, + { + 'title': "App Info", + 'route': 'appinfo', + 'perm': 'appinfo.list', + }, + { + 'title': "Configure App", + 'route': 'appinfo.configure', + 'perm': 'appinfo.configure', + }, + { + 'title': "Upgrades", + 'route': 'upgrades', + 'perm': 'upgrades.list', + }, + ], } @@ -478,7 +640,7 @@ def make_menu_entry(request, item): try: entry['url'] = request.route_url(entry['route']) except KeyError: # happens if no such route - log.warning("invalid route name for menu entry: %s", entry) + log.debug("invalid route name for menu entry: %s", entry) entry['url'] = entry['route'] entry['key'] = entry['route'] else: diff --git a/tailbone/providers.py b/tailbone/providers.py index baa2a15d..a538fa73 100644 --- a/tailbone/providers.py +++ b/tailbone/providers.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2022 Lance Edgar +# Copyright © 2010-2023 Lance Edgar # # This file is part of Rattail. # @@ -48,6 +48,9 @@ class TailboneProvider(object): def get_provided_views(self): return {} + def make_integration_menu(self, request, **kwargs): + pass + def get_all_providers(config): """