diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fc3b03..86a842c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,17 @@ ADR-007 and ADR-002. ### Added +- Dualpath "single machine" site toggle (`dualpath_single_machine`, default + on). A Dualpath relationship pair is one physical dual-bay machine (single + controller, bay-selector switch); when on, the machines list, dashboard and + machines-by-type counts, and the floor map collapse each pair to one entry + (the lower natural-sort assetnumber is PRIMARY; the SECONDARY bay is hidden) + and show a combined `2007 / 2008` label. The data model is unchanged (both + bay records always exist); detail pages stay per-bay and always show a + sibling-bay banner regardless of the toggle. Contract surface (plugin + contract bumped 0.8.0 -> 0.9.0, additive): new `shopdb.api` helpers + `resolve_dualpath_pairs` and `dualpath_single_machine_enabled`, consumed by + the machines plugin to collapse pairs contract-purely. - Relationship propagation, wired and data-driven: relationship types declare propagation-through pairs (relationshiptypepropagations M:N, replacing the never-consumed single column); creating a controls link on diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 4503c8f..b24d52a 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -135,6 +135,7 @@ read back through the API. | `pc_access_domain` | `device.geaerospace.net` | Domain appended to a PC hostname for remote-access links. Blank = hostname as-is. | | `employeeid_pattern` | `^\d{9}$` | Regex a search term must match to be treated as an employee id. Invalid regex falls back to the default and never 500s. | | `printer_hostname_template` | `Printer-{ip}.printer.geaerospace.net` | Printer hostname template. `{ip}` is the dash-separated IP address. | +| `dualpath_single_machine` | `true` | Treat a Dualpath pair (a dual-bay machine with one controller) as a single machine in the machines list, dashboard/report counts, and the floor map (the secondary bay is hidden). The data model always keeps both bay records; detail pages stay per-bay with a sibling banner. `false` lists and counts both bays separately. | ### branding diff --git a/docs/PLUGIN-HOOKS.md b/docs/PLUGIN-HOOKS.md index 8f90083..4990353 100644 --- a/docs/PLUGIN-HOOKS.md +++ b/docs/PLUGIN-HOOKS.md @@ -9,7 +9,7 @@ The contract is locked in [ADR-001](../docs/adr/ADR-001-asset-as-platform-contra The framework declares its contract version in `shopdb/__init__.py`: ```python -__contract_version__ = '0.8.0' +__contract_version__ = '0.9.0' ``` Each plugin's `manifest.json` declares the range of contract versions it supports: @@ -429,7 +429,8 @@ What `shopdb.api` exposes: `ErrorCodes` - Pagination: `get_pagination_params`, `paginate_query` - Authorization: `require_permission`, `require_role` -- Helpers: `audit_log`, `resolve_asset_position` +- Helpers: `audit_log`, `resolve_asset_position`, `resolve_dualpath_pairs`, + `dualpath_single_machine_enabled` - Import mode: `apply_import_timestamps`, `import_mode_active`, `parse_import_datetime` - Legacy employee directory: `employee_connection` @@ -482,6 +483,31 @@ position = resolve_asset_position(asset) See [ADR-001](../docs/adr/ADR-001-asset-as-platform-contract.md) for the position resolution algorithm. +### Dualpath single-machine collapse + +A Dualpath relationship pair is one physical dual-bay machine recorded as two +asset rows. When the site setting `dualpath_single_machine` is on (default), the +machines list, dashboard/report counts, and the floor map show the pair as a +single machine (the SECONDARY bay is hidden); the data model always keeps both +rows and detail pages stay per-bay. + +```python +from shopdb.api import resolve_dualpath_pairs, dualpath_single_machine_enabled + +collapse = resolve_dualpath_pairs() +# collapse.secondaryassetids: set of the non-primary bay asset ids to hide +# collapse.partnerbyasset: {assetid -> {'assetid', 'assetnumber'}} for every +# pair member (primary and secondary), for banners + +if dualpath_single_machine_enabled(): + # exclude the hidden bays and annotate the visible (primary) bay + ... +``` + +PRIMARY is the pair member with the lower natural-sort assetnumber. +`resolve_dualpath_pairs` ignores the toggle (so a detail-page sibling banner can +show always); gate the collapse itself on `dualpath_single_machine_enabled()`. + ### Import mode (legacy timestamp passthrough) Bulk imports from the classic ASP shopdb need to preserve each row's original diff --git a/frontend/src/components/ShopFloorMap.vue b/frontend/src/components/ShopFloorMap.vue index fb534cd..a54f93c 100644 --- a/frontend/src/components/ShopFloorMap.vue +++ b/frontend/src/components/ShopFloorMap.vue @@ -384,6 +384,10 @@ function renderMarkers() { typeName = item.assettype || '' } displayName = item.displayname || item.name || item.assetnumber || 'Unknown' + // Collapsed dual-bay pair: show the combined '2007 / 2008' label. + if (item.dualpathpartner) { + displayName = `${item.assetnumber} / ${item.dualpathpartner}` + } detailRoute = getAssetDetailRoute(item) } else { // Legacy machine mode diff --git a/frontend/src/views/machines/MachineDetail.vue b/frontend/src/views/machines/MachineDetail.vue index 3511c1b..0c680f4 100644 --- a/frontend/src/views/machines/MachineDetail.vue +++ b/frontend/src/views/machines/MachineDetail.vue @@ -16,6 +16,16 @@
Loading...