- Rename parser_hardware.go component type keys to canonical values: pcie -> pcie_device, psu -> power_supply - Update normalizeComponentType to map legacy aliases (pci, psu, dimm, ram, processor, network_adapter, etc.) to canonical keys; treat "null"/"-" as unknown - componentTypeTitle handles new canonical keys (pcie_device, power_supply) - Assets list: add Compare config action — opens new window with slot-diff and model-count-diff tables for selected servers - Archive Actions section spec in ui-information-architecture.md - Add tests: normalizeComponentType aliases, componentTypeTitle aliases, FlattenHardwareComponents canonical type keys Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 KiB
UI Information Architecture
Asset Page
Required section order:
Current ComponentsPrevious Components(directly below Current Components)Movement & Events(timeline cards)
Previous Components lists components that were previously installed on the asset and are currently removed.
Current Components interaction contract:
- Section header uses the same right-aligned button row pattern as
Server Card. - Buttons in header:
AddEditRemove
Current Componentsis a single filterable/selectable table (not grouped by type tables) to support bulk actions.- Table includes:
- header
Selectcheckbox (select all visible rows) - row checkboxes
- per-column filters (same visual pattern as
All Assets)
- header
- Selection is asset-page scoped and persisted in local storage keyed by asset id.
Asset page component modals:
Add Componentmodal supports two paths:Create newAttach existing
Addduplicate preflight checks:vendor_serialvendor_serial + model
- If component already exists, UI must guide user to
Attach existinginstead of creating a duplicate serial component. Attach existingmay offerForce attachwhen component is installed on another server.Edit Componentsmodal supports bulk updates for selected rows:- multi-select fields with mixed values render placeholder
variable - unique fields (
vendor serial,slot) are disabled for multi-select
- multi-select fields with mixed values render placeholder
Removemodal is de-assert-only:- requires
Status after removal(Working,Not working,Unknown) - detaches component(s) from server and sets mapped component status
- requires
- Destructive asset deletion (
Delete with details) is not shown on the asset page; it is available only inData Admin.
Asset card editing contract:
- Card has
Edittoggle. - Card shows compact component-health pizza chart (
Healthy,Unknown,Failed) for currently installed components. VendorandModelvalues inServer Cardare clickable and navigate to semantic asset list filters:/ui/asset/{vendor}/ui/asset/{vendor}/{model}
- In edit mode:
- Read-only card fields switch to editable inputs.
Editbutton changes toSave.Cancelbutton appears next toSave.
Savepersists changes throughPUT /registry/assets/{id}.Cancelreverts unsaved form values and returns to read-only mode.
Component Page
Required content:
- Component card including current firmware
- Component card values are navigable:
Vendor->/ui/component/{vendor}Model->/ui/component/{vendor}/{model}(model statistics page)Firmware(if present) -> filtered component list for same vendor/model + firmware
- Installation history table with:
- Asset
- Installed At
- Removed At
- Timeline is rendered as grouped cards (not raw event rows), same interaction model as asset page.
Timeline UX (Asset + Component Pages)
Timeline rendering rules:
- Timeline UI renders cards grouped by day, not a flat list of raw
timeline_events. - Multiple events of the same visual action in one day are visually deduplicated by
action + context. - Correlated mass operations (
correlation_id) are shown as a single bulk card with affected counts. - Asset timeline has an additional fallback collapse rule for movement cards:
Installation/Removalevents withoutcorrelation_idare collapsed bysource_type+visual_action+ 1-hour bucket.correlation_idgrouping takes precedence over the 1-hour fallback.
- Every card shows source label (
Ingest,CSV import,Manual edit,System) derived from history eventsource_type. - Every card is clickable and opens a single drilldown modal:
- left pane: concrete events in the card
- right pane: details of selected event
- no nested modal
Scope-specific timeline card content:
- On asset page, card summary must not repeat the current asset label in each row/card.
- On component page, card summary must not repeat the current component label/serial/model in each row/card.
- Instead, show the opposite side of the relation (asset on component page, component on asset page), plus slot/device when available.
- Collapsed
Installation/Removalcards render a two-column summary:- left:
Modelsas chips (32x MODEL_A,8x MODEL_B) - right:
Slotsas chips with aggregation (AOC#[1..4]) - component serials are not shown in collapsed movement cards
- raw event counts are not shown in collapsed movement cards
- left:
Timeline filters:
- Filters are server-side (history timeline API) and include:
- date range
- action
- source
- device
- slot
Part number / Model(v1 maps tomodel)- serial
- On component page, filters that are invariant for the current component scope (component serial / part number) are hidden.
- On asset page, filters that are invariant for the current asset scope are hidden.
Timeline drilldown modal:
- Card drilldown uses the same timezone (
tz) as the visible timeline grouping.
Data Admin Page
- Route:
GET /ui/history-admin - Purpose: operational/admin data repair tools and destructive maintenance actions.
- Includes:
- history batch cancel by source type (single button workflow:
Preview->Execute) Repair(single tool) with default safe actions:- restore missing timeline slots from observations
- rebuild projections (recompute)
Cleanup Orphaned Projections(count preview + confirm -> execute)Asset -> Delete with details(single button workflow:Preview->Execute delete, explicitDELETEconfirmation required)History Jobsmonitoring table (pagination, newest first, status badges, quick filters)
- history batch cancel by source type (single button workflow:
- Admin page does not expose raw JSON response blocks; all tools must render human-readable summaries/tables.
- Collapsed
Installation/Removalmodal header/meta is human-readable (Installed N components/Removed N components) and avoids rawN eventswording.
Component card editing contract:
- Card has
Edittoggle with the same mode behavior as asset card (Edit->Save, showCancel). Savepersists changes throughPUT /registry/components/{id}.Cancelreverts unsaved form values.
Failures Page
Route: GET /ui/failures
Required section order:
Active FailuresFailure Chronology
Active Failures lists unresolved failure incidents (no later replacement in the same slot on the same server).
Failure Chronology includes:
- failure events
- repair-by-replacement derived entries (new component installed in the same slot on the same server after failure)
Failure detail page:
- Routes:
- primary:
GET /ui/failure/{failure_id} - compatibility alias:
GET /ui/failures/{failure_id}
- primary:
Active Failurestable links fromFailure TimeandDetailsopen the failure detail page.- Page aggregates incident context:
- server and failed component
- component install time into server (when available)
- failure time
- repair-by-replacement details (if detected)
- open duration
Repair / Replacementsection must present replacement comparison as paired rows:Model (old / new)Serial (old / new)
- Avoid redundant duplicate serial rendering across summary blocks when the same identifiers are already shown in the repair comparison.
Open Durationon failure detail page is date-precision (whole days), not hour/minute precision.
Manual failure registration UI contract:
- page header includes
Register Failureaction button - opens modal for manual failure input
- fields are text inputs with suggestions (datalist/autocomplete style):
- server serial
- location
- component serial (suggestion label includes model on the same line)
- failure date (
YYYY-MM-DD, default = today) - description
- component serial is required to submit
- if component serial is recognized and current installation is known, server serial is auto-filled
- if location is selected and maps uniquely, component serial is auto-filled; if ambiguous, UI shows candidate list for explicit selection
- server serial and location suggestions/filtering are linked (server narrows location suggestions)
- submit requires explicit confirmation step showing entered and recognized data before request is sent
List Pages
Creation flows:
- Assets list page provides
New Assetaction that opens modal form and creates entity viaPOST /assets. - Components list page provides
New Componentaction that opens modal form and creates entity viaPOST /components.
Shared list behavior:
- Every table-based list in UI pages must provide pagination in one shared visual style:
- Summary:
Showing X–Y of N - Navigation:
Prev, page links with ellipsis when needed,Next - Query contract: page number is controlled through URL query (
pagefor list pages, section-specific keys for multi-list pages such as dashboard).
- Summary:
- Every table header must provide per-column text filtering:
- A filter input is rendered under each column header.
- Filtering is case-insensitive and applies as substring match.
- Filtering semantics are global for the list/query scope: filters apply to the full result set before pagination, not only to the currently rendered page/slice.
- Page-local header filtering (client-side filtering over only visible rows of a paginated table) is not allowed for primary list pages because it produces misleading results.
- Input suggestions/datalists should be derived from the full filtered list/query scope (or a server-provided option set for that scope), not only from the current page.
- Changing any header filter resets the corresponding pagination query parameter to page 1.
List behavior checklist (page-by-page):
/ui/asset(assets list /All Assets):- per-column filters: server-side, global scope (full dataset before pagination)
- pagination: single list (
page) - selection: global across pages (persistent client storage)
/ui/component(components list):- per-column filters: server-side, global scope (full dataset before pagination)
- pagination: single list (
page) - selection: none (row navigation only)
/ui/failureand/ui/failures(failures page):Active Failures: paginated section (active_page)Failure Chronology: paginated section (chronology_page)- page-local auto header filters are disabled on paginated tables unless replaced with server-side global filters for that section
- manual registration modal suggestions are derived from page data / server-provided option sets, not from visible rows
/ui/search(global search):- result sections (
Assets,Components,Failure events) use independent pagination - generic page-local auto header filters are disabled on paginated result tables
- if/when header filters are added to search sections, they must be server-side and section-scoped before pagination
- result sections (
/ui(dashboard):- dashboard tables/lists use independent pagination per section
- generic page-local auto header filters are disabled on paginated dashboard tables
- any future header filters must be server-side and applied before section pagination
/ui/component/{vendor}/{model}(model stats page):Servers With Installed Components Of This Model: independent pagination (servers_page)Components Of This Model: independent pagination (components_page)- generic page-local auto header filters are disabled on both paginated tables unless replaced with server-side global filters
/ui/asset/{id}and/ui/component/{id}(detail pages):- embedded historical tables may be unpaginated
- local-only filtering is acceptable only for explicitly unpaginated tables; paginated tables on detail pages must follow the shared global-filter rule
Assets list specifics:
All Assetstable filtering is server-side and applies to the full dataset before pagination.Actionssection includes:New AssetCompare config(opens in a separate window/tab, compares hardware composition for selected servers, shows differences)Delete Selected (With Details)
All Assetssupports global bulk selection:- Header
Selectcheckbox can select all assets across all pagination pages.
- Header
- Selected IDs persist across page navigation and are stored in browser local storage.
- Global-selection semantics for paginated list bulk actions must be explicit and must not silently degrade to current-page-only selection.
Component model statistics page (/ui/component/{vendor}/{model}):
Model Statisticssection includes:- counts (
Total,Installed,Uninstalled,Healthy,Unknown,Failed) - compact pizza chart (status distribution:
Healthy,Uninstalled,Failed,Unknown)
- counts (
Servers With Installed Components Of This Modeltable:- status-filter chips
- independent pagination (
servers_page)
Components Of This Modeltable (same page, below servers):- component rows with status, asset, firmware
- independent pagination (
components_page)
Global Search
- UI top bar provides a global search form available on all pages.
- Global search page (
/ui/search) searches across:- Assets
- Components
- Failure events
- Results are split by entity type and paginated independently per section.
Supporting Repositories Required By UI
timeline.EventRepository.ListLatestBySubjectsAndEventTypes(...)registry.InstallationRepository.ListPreviousComponentsByAsset(...)registry.InstallationRepository.ListInstallationHistoryByComponent(...)