Tab the PC detail page and add panel groups to the ADR-010 contract
This commit is contained in:
@@ -104,7 +104,7 @@ from .plugins import plugin_manager
|
||||
# defeated by rotating the header. The helper resolves from remote_addr, which
|
||||
# ProxyFix has already filled from the header when TRUSTED_PROXY_COUNT says a
|
||||
# proxy is really in front. Additive names on the surface, minor bump.
|
||||
__contract_version__ = '0.28.0'
|
||||
__contract_version__ = '0.29.0'
|
||||
|
||||
# Product release version (see ADR-007). The product version and the
|
||||
# plugin-contract version above are distinct series with independent
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -370,8 +370,23 @@ class BasePlugin(ABC):
|
||||
# ('list' takes a 'map' of title/badge/meta
|
||||
# keys, rendered generically - see warranty)
|
||||
'position': int, # order among panels
|
||||
'group': str, # OPTIONAL. Which tab on the detail page:
|
||||
# 'details' | 'software' | 'metrics'
|
||||
# | 'actions' | 'activity'. Omitted means
|
||||
# 'details'.
|
||||
}
|
||||
|
||||
ON 'group'. The detail pages are tabbed, and a panel says which tab it
|
||||
belongs to rather than the page listing panels by id - a page that knew
|
||||
its plugins' panels by name would defeat the point of the hook.
|
||||
|
||||
Omitting it is the correct answer for most panels and keeps every
|
||||
existing plugin working untouched: an unknown or absent group resolves
|
||||
to 'details', which is the tab that holds what an asset IS. Reach for
|
||||
another group only when the panel is the thing that tab exists for -
|
||||
an inventory listing, live telemetry, controls that act on the machine,
|
||||
or a history feed.
|
||||
|
||||
Consumed by GET /api/pluginui/asset-panels?assetid=<id>, which returns
|
||||
the panels matching that asset's type. Disabled plugins
|
||||
are skipped; a broken plugin is isolated in prod, re-raised in dev/test.
|
||||
|
||||
Reference in New Issue
Block a user