Surface the endpoint inventory, and let an event show its message

The hardware, OS and storage inventory had columns and data but nowhere to
be read: the only per-PC card was the status keyvalue, so a machine's
processor, firmware, disks and listening ports were reachable only by
querying the database.

Adds four Monitors cards - Hardware, Operating system, Storage, Listening
ports - split by the question each answers rather than by which JSON blob
they came from. OS and BIOS share one card deliberately; apart they are
three short rows each. A card yields no fields when its columns are null,
so an endpoint on an older agent hides them rather than showing a grid of
blanks.

User context is declared last on the page. The probe feeding it is not yet
producing output, so it reads empty for now, and being last means an empty
card sits below the populated ones instead of pushing them down.

The Activity feed showed a title and an event id, but the title is the
catalog name for that id - the same text on every occurrence - so two
different faults read identically. Rows now carry the provider name, and
the stored message body expands in place when the severity badge is
clicked. Commands expand to their result message, which is the reason a
failed one failed.

The badge doubles as the expander rather than gaining a control beside it,
and it keeps its severity label when open: swapping that for "Hide" would
cost the at-a-glance severity scan down the feed. Being a button rather
than a span, it is also now keyboard reachable.

map.body is additive in the shared renderer - panels that do not declare
it render exactly as before.
This commit is contained in:
benjamin.baker
2026-09-04 19:14:16 -04:00
parent 862b290545
commit 9ac711ce2d
6 changed files with 580 additions and 17 deletions

View File

@@ -69,7 +69,7 @@ def test_endpoints_asset_panels_are_computer_scoped():
"""Every asset panel targets computer assets only, with an endpoint."""
plugin = EndpointsPlugin()
panels = plugin.get_asset_panels()
assert len(panels) == 7
assert len(panels) == 12
for panel in panels:
assert panel['assettypes'] == ['computer']
assert panel['endpoint'].startswith('/api/endpoints/')
@@ -220,18 +220,21 @@ def test_known_payload_keys_cover_persisted_and_relayed_fields():
assert persisted_or_relayed <= KNOWN_PAYLOAD_KEYS
def test_new_hardware_telemetry_keys_are_logged_not_silently_known():
"""Disk/bios/memory inventory is collected at the agent before the server
persists it. Those keys must be OUTSIDE the known set so ingest logs them
rather than dropping them silently."""
def test_hardware_telemetry_keys_are_persisted_not_merely_logged():
"""Disk/bios/memory/processor/osinfo inventory was collected at the agent and
logged as unknown keys for several versions while the shapes were proven
against real endpoint traffic. They have columns now (endpoints migration
0013), so they must be INSIDE the known set - leaving them out would log
every report as carrying unpersisted keys while the ingest quietly stores
them, which is the most misleading combination available."""
from plugins.endpoints.plugin import KNOWN_PAYLOAD_KEYS
for key in ('disks', 'bios', 'memory', 'processor', 'osinfo', 'domain'):
assert key not in KNOWN_PAYLOAD_KEYS
for key in ('disks', 'bios', 'memory', 'processor', 'osinfo', 'domain',
'pendingreboot', 'usercontext'):
assert key in KNOWN_PAYLOAD_KEYS
# 'applications' USED to be in this list. It is persisted now - that is what
# the installed-software work added - so it belongs in the known set, and
# asserting its absence would fail the moment the feature it tests works.
# 'applications' followed this same staging path earlier and is likewise
# persisted, to its own endpointapplications table rather than a state blob.
assert 'applications' in KNOWN_PAYLOAD_KEYS