Tab the PC detail page and add panel groups to the ADR-010 contract

This commit is contained in:
2026-08-31 14:25:53 -04:00
parent 73a91ef916
commit 0d49341a2a
8 changed files with 315 additions and 20 deletions

View File

@@ -19,6 +19,14 @@ from shopdb.utils.authz import require_permission
pluginui_bp = Blueprint('pluginui', __name__)
# The tabs an asset detail page offers, and so the only values a panel's
# 'group' may take. Kept here rather than in the frontend because the server
# resolves the group before the client sees it - see asset_panels below.
#
# 'details' is first and is the fallback: it holds what an asset IS, which is
# what a panel declaring nothing almost always contributes.
ASSET_PANEL_GROUPS = ('details', 'software', 'metrics', 'actions', 'activity')
def _collect(hookname):
"""Aggregate a data-only hook across enabled plugins.
@@ -67,6 +75,12 @@ def asset_panels():
Query param assetid is required. A panel matches when its assettypes list
contains the asset's type key or the wildcard '*'.
Every panel comes back carrying a 'group', naming the detail-page tab it
belongs to. It is resolved HERE rather than in the client so a plugin that
predates tabs, or names a group that does not exist, still lands somewhere a
person can see instead of vanishing from a page that only renders known
groups. Unknown and absent both mean 'details'.
"""
assetid = request.args.get('assetid', type=int)
if not assetid:
@@ -81,6 +95,9 @@ def asset_panels():
for panel in _collect('get_asset_panels'):
assettypes = panel.get('assettypes') or []
if '*' in assettypes or (assettype and assettype in assettypes):
panel = dict(panel)
group = str(panel.get('group') or '').strip().lower()
panel['group'] = group if group in ASSET_PANEL_GROUPS else 'details'
matched.append(panel)
matched.sort(key=lambda panel: panel.get('position', 99))
return success_response(matched)