nav items declare their permission
This commit is contained in:
@@ -115,6 +115,15 @@ ADR-007 and ADR-002.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **The sidebar offered pages the reader could not open, and hid ones they
|
||||
could.** A nav item is hidden from anybody who does not hold its permission,
|
||||
but only four items ever declared one - so the filter did nothing for the
|
||||
rest, and a signed-out visitor granted `machines.view` still saw an empty
|
||||
sidebar. Every item now names the read permission its page needs, in the
|
||||
plugins, in the core navigation endpoint and in the frontend's fallback list.
|
||||
A signed-in member with a sparse role will notice the same correction: a link
|
||||
that could only answer 403 no longer appears.
|
||||
|
||||
- **Every report offers to email itself, not just two of them.** `POST
|
||||
/api/reports/email` has always taken any `{columns, rows}`, but the button was
|
||||
on the toner and warranty pages only - because those two happen to be their
|
||||
|
||||
@@ -187,18 +187,18 @@ const iconMap = {
|
||||
|
||||
// Default navigation (used as fallback if API fails)
|
||||
const defaultNav = [
|
||||
{ name: 'Dashboard', icon: 'layout-dashboard', route: '/', position: 0 },
|
||||
{ name: 'Notifications', icon: 'bell', route: '/notifications', position: 5 },
|
||||
{ name: 'Calendar', icon: 'calendar', route: '/calendar', position: 6 },
|
||||
{ name: 'Map', icon: 'map', route: '/map', position: 4 },
|
||||
{ name: 'Machines', icon: 'cog', route: '/machines', position: 10, section: 'assets' },
|
||||
{ name: 'PCs', icon: 'desktop', route: '/pcs', position: 15, section: 'assets' },
|
||||
{ name: 'Network', icon: 'network-wired', route: '/network', position: 18, section: 'assets' },
|
||||
{ name: 'Printers', icon: 'printer', route: '/printers', position: 20, section: 'assets' },
|
||||
{ name: 'USB Devices', icon: 'usb', route: '/usb', position: 25, section: 'assets' },
|
||||
{ name: 'Applications', icon: 'app-window', route: '/applications', position: 30, section: 'information' },
|
||||
{ name: 'Knowledge Base', icon: 'book-open', route: '/knowledgebase', position: 35, section: 'information' },
|
||||
{ name: 'Reports', icon: 'bar-chart-3', route: '/reports', position: 40, section: 'information' },
|
||||
{ name: 'Dashboard', icon: 'layout-dashboard', route: '/', position: 0, permission: 'assets.view' },
|
||||
{ name: 'Notifications', icon: 'bell', route: '/notifications', position: 5, permission: 'notifications.view' },
|
||||
{ name: 'Calendar', icon: 'calendar', route: '/calendar', position: 6, permission: 'notifications.view' },
|
||||
{ name: 'Map', icon: 'map', route: '/map', position: 4, permission: 'assets.view' },
|
||||
{ name: 'Machines', icon: 'cog', route: '/machines', position: 10, section: 'assets', permission: 'machines.view' },
|
||||
{ name: 'PCs', icon: 'desktop', route: '/pcs', position: 15, section: 'assets', permission: 'computers.view' },
|
||||
{ name: 'Network', icon: 'network-wired', route: '/network', position: 18, section: 'assets', permission: 'network.view' },
|
||||
{ name: 'Printers', icon: 'printer', route: '/printers', position: 20, section: 'assets', permission: 'printers.view' },
|
||||
{ name: 'USB Devices', icon: 'usb', route: '/usb', position: 25, section: 'assets', permission: 'usb.view' },
|
||||
{ name: 'Applications', icon: 'app-window', route: '/applications', position: 30, section: 'information', permission: 'applications.view' },
|
||||
{ name: 'Knowledge Base', icon: 'book-open', route: '/knowledgebase', position: 35, section: 'information', permission: 'kb.view' },
|
||||
{ name: 'Reports', icon: 'bar-chart-3', route: '/reports', position: 40, section: 'information', permission: 'reports.view' },
|
||||
]
|
||||
|
||||
// The canonical sidebar sections, in the order they render. A nav item DECLARES
|
||||
|
||||
@@ -1652,6 +1652,7 @@ class ComputersPlugin(BasePlugin):
|
||||
'name': 'PCs',
|
||||
'icon': 'desktop',
|
||||
'route': '/pcs',
|
||||
'permission': 'computers.view',
|
||||
'position': 15,
|
||||
'section': 'assets',
|
||||
},
|
||||
|
||||
@@ -68,6 +68,7 @@ class KnowledgeBasePlugin(BasePlugin):
|
||||
'name': 'Knowledge Base',
|
||||
'icon': 'book-open',
|
||||
'route': '/knowledgebase',
|
||||
'permission': 'kb.view',
|
||||
'position': 35,
|
||||
'section': 'information',
|
||||
},
|
||||
|
||||
@@ -231,6 +231,7 @@ class MachinesPlugin(BasePlugin):
|
||||
'name': 'Machines',
|
||||
'icon': 'cog',
|
||||
'route': '/machines',
|
||||
'permission': 'machines.view',
|
||||
'position': 10,
|
||||
'section': 'assets',
|
||||
},
|
||||
|
||||
@@ -73,6 +73,7 @@ class MeasuringToolsPlugin(BasePlugin):
|
||||
'name': 'Measuring Tools',
|
||||
'icon': 'ruler',
|
||||
'route': '/measuringtools',
|
||||
'permission': 'measuringtools.view',
|
||||
'position': 22,
|
||||
'section': 'assets',
|
||||
},
|
||||
@@ -86,6 +87,7 @@ class MeasuringToolsPlugin(BasePlugin):
|
||||
'description': 'Measuring tools bucketed by calibration status',
|
||||
'category': 'compliance',
|
||||
'route': '/reports/calibration',
|
||||
'permission': 'measuringtools.view',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -207,6 +207,7 @@ class NetworkPlugin(BasePlugin):
|
||||
'name': 'Network',
|
||||
'icon': 'network-wired',
|
||||
'route': '/network',
|
||||
'permission': 'network.view',
|
||||
'position': 18,
|
||||
'section': 'assets',
|
||||
},
|
||||
|
||||
@@ -232,12 +232,14 @@ class NotificationsPlugin(BasePlugin):
|
||||
'name': 'Notifications',
|
||||
'icon': 'bell',
|
||||
'route': '/notifications',
|
||||
'permission': 'notifications.view',
|
||||
'position': 5,
|
||||
},
|
||||
{
|
||||
'name': 'Calendar',
|
||||
'icon': 'calendar',
|
||||
'route': '/calendar',
|
||||
'permission': 'notifications.view',
|
||||
'position': 6,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -385,6 +385,7 @@ class PrintersPlugin(BasePlugin):
|
||||
'name': 'Printers',
|
||||
'icon': 'printer',
|
||||
'route': '/printers',
|
||||
'permission': 'printers.view',
|
||||
'position': 20,
|
||||
'section': 'assets',
|
||||
},
|
||||
|
||||
@@ -185,6 +185,7 @@ class USBPlugin(BasePlugin):
|
||||
'name': 'USB Devices',
|
||||
'icon': 'usb',
|
||||
'route': '/usb',
|
||||
'permission': 'usb.view',
|
||||
'position': 25,
|
||||
'section': 'assets',
|
||||
},
|
||||
|
||||
@@ -57,6 +57,7 @@ class WarrantyPlugin(BasePlugin):
|
||||
'name': 'Warranties',
|
||||
'icon': 'shield',
|
||||
'route': '/warranties',
|
||||
'permission': 'warranty.view',
|
||||
'position': 9,
|
||||
},
|
||||
]
|
||||
@@ -69,6 +70,7 @@ class WarrantyPlugin(BasePlugin):
|
||||
'description': 'Assets bucketed by coverage: expired, expiring soon, active',
|
||||
'category': 'warranty',
|
||||
'route': '/reports/warranty',
|
||||
'permission': 'warranty.view',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -155,9 +155,14 @@ def get_navigation():
|
||||
all_items = []
|
||||
|
||||
# Core navigation items (always present)
|
||||
# Every item names the permission its page needs, so the filter below can
|
||||
# hide what the caller cannot reach - a link that only leads to a 401 is
|
||||
# worse than no link.
|
||||
all_items.extend([
|
||||
{'name': 'Dashboard', 'icon': 'layout-dashboard', 'route': '/', 'position': 0},
|
||||
{'name': 'Map', 'icon': 'map', 'route': '/map', 'position': 4},
|
||||
{'name': 'Dashboard', 'icon': 'layout-dashboard', 'route': '/',
|
||||
'position': 0, 'permission': 'assets.view'},
|
||||
{'name': 'Map', 'icon': 'map', 'route': '/map', 'position': 4,
|
||||
'permission': 'assets.view'},
|
||||
])
|
||||
|
||||
# Collect navigation items from enabled plugins. Disabling persists to the
|
||||
@@ -181,8 +186,11 @@ def get_navigation():
|
||||
|
||||
# Add core information section items
|
||||
all_items.extend([
|
||||
{'name': 'Applications', 'icon': 'app-window', 'route': '/applications', 'position': 30, 'section': 'information'},
|
||||
{'name': 'Reports', 'icon': 'bar-chart-3', 'route': '/reports', 'position': 40, 'section': 'information'},
|
||||
{'name': 'Applications', 'icon': 'app-window', 'route': '/applications',
|
||||
'position': 30, 'section': 'information',
|
||||
'permission': 'applications.view'},
|
||||
{'name': 'Reports', 'icon': 'bar-chart-3', 'route': '/reports',
|
||||
'position': 40, 'section': 'information', 'permission': 'reports.view'},
|
||||
])
|
||||
|
||||
# Sort by position
|
||||
|
||||
Reference in New Issue
Block a user