diff --git a/bible-local/architecture/system-overview.md b/bible-local/architecture/system-overview.md index 9eebb00..399c4a0 100644 --- a/bible-local/architecture/system-overview.md +++ b/bible-local/architecture/system-overview.md @@ -10,7 +10,8 @@ It is designed to be embedded as a module in other Go applications that already - Render one Reanimator JSON snapshot as HTML - Read-only presentation of top-level metadata and hardware sections -- Tabular rendering for arrays such as `cpus`, `memory`, `storage`, `pcie_devices`, `power_supplies`, and sensor subsections +- Tabular rendering for arrays such as `cpus`, `memory`, `storage`, `pcie_devices`, `power_supplies`, `event_logs`, and sensor subsections +- Object rendering for singleton/config sections such as `board` and `platform_config` - Status color coding for fast scanning - Lightweight section navigation - Standalone HTML rendering or embeddable HTTP handler diff --git a/bible-local/architecture/ui-information-architecture.md b/bible-local/architecture/ui-information-architecture.md index c0a1b59..fe6610c 100644 --- a/bible-local/architecture/ui-information-architecture.md +++ b/bible-local/architecture/ui-information-architecture.md @@ -30,13 +30,16 @@ Preferred order: 6. `pcie_devices` 7. `power_supplies` 8. `sensors` -9. unknown sections +9. `event_logs` +10. `platform_config` +11. unknown sections ## Section Presentation - singleton object sections render as key-value table - array sections render as compact data tables - sensors render as separate subtables for `fans`, `power`, `temperatures`, and `other` +- `platform_config` renders as a key-value table without interpreting setting names or values ## Visual Rules diff --git a/viewer/render.go b/viewer/render.go index d2787cf..bb43a46 100644 --- a/viewer/render.go +++ b/viewer/render.go @@ -19,21 +19,25 @@ var sectionOrder = []string{ "pcie_devices", "power_supplies", "sensors", + "event_logs", + "platform_config", } var sectionTitles = map[string]string{ - "board": "Board", - "firmware": "Firmware", - "cpus": "CPUs", - "memory": "Memory", - "storage": "Storage", - "pcie_devices": "PCIe Devices", - "power_supplies": "Power Supplies", - "sensors": "Sensors", - "fans": "Fans", - "power": "Power", - "temperatures": "Temperatures", - "other": "Other", + "board": "Board", + "firmware": "Firmware", + "cpus": "CPUs", + "memory": "Memory", + "storage": "Storage", + "pcie_devices": "PCIe Devices", + "power_supplies": "Power Supplies", + "sensors": "Sensors", + "event_logs": "Event Logs", + "platform_config": "Platform Config", + "fans": "Fans", + "power": "Power", + "temperatures": "Temperatures", + "other": "Other", } var preferredMetaKeys = []string{"target_host", "collected_at", "source_type", "protocol", "filename"} @@ -73,9 +77,10 @@ var preferredColumns = map[string][]string{ "firmware": {"device_name", "version"}, "cpus": {"model", "clock", "cores", "threads", "l1", "l2", "l3", "microcode", "socket"}, "memory": {"part_number", "serial_number", "slot"}, - "storage": {"type", "model", "serial_number", "firmware", "size_gb", "slot"}, + "storage": {"type", "model", "serial_number", "firmware", "size_gb", "logical_block_size_bytes", "physical_block_size_bytes", "metadata_bytes_per_block", "slot"}, "pcie_devices": {"device_class", "manufacturer", "model", "serial_number", "mac_addresses", "slot", "numa_node", "link_speed", "link_width", "bdf"}, "power_supplies": {"vendor", "model", "part_number", "serial_number", "slot"}, + "event_logs": {"severity_icon", "source", "event_time", "severity", "message_id", "message", "component_ref", "fingerprint", "is_active", "raw_payload"}, "fans": {"name", "rpm"}, "power": {"name", "voltage_v", "current_a", "power_w"}, "temperatures": {"name", "celsius", "threshold_warning_celsius", "threshold_critical_celsius"}, diff --git a/viewer/render_test.go b/viewer/render_test.go index 0cbf6e3..dc89068 100644 --- a/viewer/render_test.go +++ b/viewer/render_test.go @@ -339,3 +339,81 @@ func TestRenderHTMLAddsSeverityFilterForEventLogs(t *testing.T) { t.Fatalf("expected synthetic severity icon column header to remain visually empty") } } + +func TestRenderHTMLDisplaysHardwareContract210Fields(t *testing.T) { + snapshot := []byte(`{ + "filename": "redfish://10.10.10.103", + "source_type": "api", + "protocol": "redfish", + "target_host": "10.10.10.103", + "collected_at": "2026-02-10T15:30:00Z", + "hardware": { + "board": { + "manufacturer": "Supermicro", + "product_name": "X12DPG-QT6", + "serial_number": "21D634101" + }, + "storage": [ + { + "slot": "OB01", + "type": "NVMe", + "model": "INTEL SSDPF2KX076T1", + "size_gb": 7680, + "logical_block_size_bytes": 512, + "physical_block_size_bytes": 4096, + "metadata_bytes_per_block": 8, + "serial_number": "BTAX41900GF87P6DGN", + "manufacturer": "Intel", + "firmware": "9CV10510", + "interface": "NVMe", + "present": true, + "status": "OK" + } + ], + "event_logs": [ + { + "source": "redfish", + "event_time": "2026-03-15T14:03:20Z", + "severity": "Info", + "message_id": "OpenBMC.0.1.SystemReboot", + "message": "System reboot requested by administrator", + "component_ref": "Mainboard" + } + ], + "platform_config": { + "SecureBoot": "Enabled", + "BiosVersion": "06.08.05", + "TpmEnabled": true, + "NumaEnabled": false, + "HyperThreading": "Enabled" + } + } +}`) + + html, err := RenderHTML(snapshot, "Reanimator Chart") + if err != nil { + t.Fatalf("RenderHTML() error = %v", err) + } + + text := string(html) + for _, needle := range []string{ + "Storage", + "Event Logs", + "Platform Config", + "logical_block_size_bytes", + "physical_block_size_bytes", + "metadata_bytes_per_block", + "512", + "4096", + "8", + "SecureBoot", + "Enabled", + "TpmEnabled", + "true", + "System reboot requested by administrator", + } { + if !strings.Contains(text, needle) { + t.Fatalf("expected rendered html to contain %q", needle) + } + } +}