The rack's link picker read `/nodes`, so it only ever offered devices
someone had already approved onto a logical canvas — two rows on a homelab
holding 74 inventory entries. A device on no canvas is still the record of
a real box, and is exactly what a rack is built out of.
`DevicePickerModal` replaces `NodePickerModal` and lists the Device
Inventory itself. Picking an entry calls the new `relinkDevice`, which
repoints the mount's `deviceId`, adopts that entry's node, status and —
unless the user renamed the plate — its label. One entry, one mount: a row
another plate stands for is not offered, and the store refuses it anyway.
The placeholder a rack-created plate left behind is dropped through the new
`DELETE /api/v1/scan/pending/{id}`, which refuses a device a rack still
mounts (409): foreign keys are off at runtime, so the mount would be left
naming a row that no longer exists.
`LinkedDevicePanel` becomes "Linked device" and now prints what discovery
found even when nothing on a canvas answers for the device; only the
canvas-side rows go missing, under a "Not on a logical canvas." note.
Also renames `pending_devices` to `device_inventory` (and
`pending_device_links` to `device_inventory_links`), with the Python and
TypeScript names that followed it. "Pending devices" was the scanner's word
for a queue of finds awaiting approval; the rows outlive approval, are
edited by hand and are what a rack mounts. Routes, payload keys and MCP
tool names are a published contract and are unchanged — `/scan/pending/*`
and the `pending_devices` key in `/stats` stay as they are.
The rename migration runs before `create_all`, or an empty new table would
be created beside the populated old one and every scanned device would read
as gone; it repairs that state too, for anyone whose app already started
mid-upgrade. Foreign keys are switched on for the rename so SQLite rewrites
the `REFERENCES` clause in `rack_devices`.
ha-relevant: maybe
248 lines
11 KiB
Markdown
248 lines
11 KiB
Markdown
# Rack Canvas
|
|
|
|
A rack canvas is the **physical** counterpart to the network diagram: real racks,
|
|
the gear mounted in them, and the patch cables between their ports. It is a
|
|
canvas kind of its own — you create it like any other canvas, and Homelable swaps
|
|
the renderer when you switch to it.
|
|
|
|
Where the diagram answers *what talks to what*, the rack answers *what is where*:
|
|
which U a machine sits in, what plate it wears, which switch port its uplink
|
|
lands on.
|
|
|
|
> Works with **and** without the backend. In the no-backend standalone/demo build
|
|
> a rack canvas persists to your browser's local storage; the Device Inventory
|
|
> picker and the live status check are backend-only (marked 🔒 below).
|
|
|
|
---
|
|
|
|
## Feature Overview
|
|
|
|
- **Racks** — any U height, 19" or 10" wide, bottom-up or top-down numbering, per-rack frame / rail / interior colours, open or enclosed.
|
|
- **Mounted gear** — a device occupies a U range and part of a 12-column width grid, so half- and third-width machines share a U.
|
|
- **Faceplates** — a visual catalog of plates (servers, switches, routers, patch panels, UPS, PDUs, desktop NAS towers, shelves, blanks, cable managers) drawn as vector artwork that scales with the rack.
|
|
- **Ports & patching** — RJ45 and SFP ports per device, cabled port-to-port by dragging from one to the other, across racks if needed.
|
|
- **Device Inventory** 🔒 — a mount points at a real inventory entry, so a rack shows the same devices your scans found, and gear you rack by hand joins that inventory.
|
|
- **Live status** 🔒 — a mount can follow the status check already configured on the matching diagram node, and light its plate LED accordingly.
|
|
- **Import links** 🔒 — derive patches from the physical links already drawn on your diagrams, as often as you like.
|
|
|
|
---
|
|
|
|
## Create a rack canvas
|
|
|
|
1. Open the **canvas switcher** at the top of the left sidebar.
|
|
2. Click **New Canvas**.
|
|
3. Under **Kind**, pick **Rack** (the other kind, *Diagram*, is the usual node/link canvas).
|
|
4. Name it, pick an icon, and create.
|
|
|
|
A canvas cannot change kind afterwards — a diagram and a rack store different
|
|
things. Deleting a rack canvas deletes its racks, mounts and cables with it;
|
|
duplicating a canvas duplicates them too.
|
|
|
|
---
|
|
|
|
## Add a rack
|
|
|
|
**Add Rack** in the header drops a new rack on the canvas. Drag it anywhere; a
|
|
canvas can hold as many as you like, and cables can run between them.
|
|
|
|
**Double-click the rack chrome** (the frame, not a device) to open its settings:
|
|
|
|
| Setting | What it does |
|
|
|---|---|
|
|
| Name / Location | Free text — "Baie salon", "Garage", … |
|
|
| U height | How many mountable U the rack has (42 by default). |
|
|
| Width | 19" or 10" — drives the drawn inner width. |
|
|
| Numbering | `bottom-up` or `top-down`. **Labels only** — gear never moves. |
|
|
| Show U numbers | Print the U scale on the rails. |
|
|
| Enclosed | Draw side panels / a closed chassis. |
|
|
| Colours | Frame, rails and interior. Defaults come from your app theme. |
|
|
| Delete | Removes the rack and everything mounted in it. |
|
|
|
|
---
|
|
|
|
## Mount a device
|
|
|
|
Click **+ Device** in the left sidebar, or drag an accessory from the sidebar
|
|
tray straight onto a rack. The device modal offers three sources:
|
|
|
|
- **Device Inventory entry** 🔒 — pick something already discovered. The field
|
|
opens the real Device Inventory, with its search, source and type filters, and
|
|
it opens pre-filtered to **rackable** hardware (no light bulbs, no sockets).
|
|
A device already mounted on this canvas is refused.
|
|
- **New device** — for hardware no scan can find (a patch panel, a PDU, an
|
|
unmanaged switch). It is created as a normal Device Inventory entry tagged
|
|
**Rack devices**, so you can search, filter, hide and delete it like any other.
|
|
- **Accessory** — rack-only furniture: blanking plate, shelf, cable manager.
|
|
These are not devices and never appear in the inventory.
|
|
|
|
Then set:
|
|
|
|
| Field | Notes |
|
|
|---|---|
|
|
| Label | Shown on the plate. |
|
|
| Faceplate | Opens the visual catalog — see below. |
|
|
| U position / height | `U` is counted **from the bottom rail**, whatever the numbering setting prints. |
|
|
| Column / width | Full, half, third, sixth or quarter of the rack width. |
|
|
| Status | A fixed colour, or **Check device** 🔒 — see below. |
|
|
| Colour | Overrides the plate's default tint. |
|
|
| Ports | The list of RJ45 / SFP ports, seeded by the faceplate and editable afterwards. |
|
|
|
|
**Double-click a plate** to reopen this modal on an existing mount; a single
|
|
click only selects it. **Unmount** takes the device out of the rack — it stays in
|
|
the Device Inventory.
|
|
|
|
### Linked device 🔒
|
|
|
|
Under the port list, a mount that stands for a real device prints what is known
|
|
about that box: name, type, hostname, IP, MAC, OS, the status check it runs, the
|
|
canvas it is drawn on, when it was last seen, and the services discovery
|
|
fingerprinted on it.
|
|
|
|
It is read-only — edit those facts in the Device Inventory or on the logical
|
|
canvas, not in the rack — and an accessory shows nothing at all. A device that is
|
|
on no diagram still prints everything discovery found about it; only the
|
|
canvas-side lines go missing, and the panel says *Not on a logical canvas.*
|
|
|
|
**Link to another device…** points the plate at a different Device Inventory
|
|
entry — the whole inventory, not just the devices you approved onto a diagram.
|
|
Use it when you created the gear from the rack (the entry starts empty, with just
|
|
a name) or when the plate ended up on the wrong twin of two look-alike hosts. The
|
|
plate takes the entry's IP, MAC, services, status and — unless you renamed it —
|
|
its name, **Check device** becomes available if that device is on a diagram, and
|
|
the link is saved with the rest of the canvas. A device already mounted elsewhere
|
|
in the design is not offered: one entry, one plate. The empty placeholder the
|
|
rack created for the plate is removed from the inventory once nothing uses it.
|
|
|
|
### Placement rules
|
|
|
|
- A drop **snaps to the nearest free slot**; a placement that cannot work
|
|
previews in red.
|
|
- Drag a mounted device inside its rack to move it — same snapping.
|
|
- **Growing** a device, by hand or by picking a taller plate, relocates it to the
|
|
nearest slot that takes the new size. Only a rack with no such slot refuses the
|
|
edit, and it tells you so.
|
|
|
|
---
|
|
|
|
## Faceplates
|
|
|
|
The **Faceplate** field opens a catalog, not a dropdown of names: every plate is
|
|
drawn with the real renderer, at its real relative width and U height, grouped by
|
|
family and searchable.
|
|
|
|
| Family | Examples |
|
|
|---|---|
|
|
| Servers | 1U, 1U with drive bays, 2U with bays, 4U storage, half-width SFF, third-width mini PC |
|
|
| Network | 8 / 24 / 48-port switches, 1U router |
|
|
| Patch | 24-port copper panel, 12-port fibre panel |
|
|
| Storage | 2U NAS, desktop NAS towers in 2, 4 and 5 bays |
|
|
| Power | 2U UPS, 1U PDU |
|
|
| Accessories | Blanking plate, shelf, cable manager |
|
|
|
|
Picking a plate **reseeds the ports** it comes with; your own port edits are kept
|
|
until you change plate again. Plates are drawn as vector artwork in relative
|
|
coordinates, so they stay correct at any rack width and U height, and their
|
|
colours follow the active app theme.
|
|
|
|
---
|
|
|
|
## Ports and patching
|
|
|
|
Ports are **RJ45** or **SFP/SFP+**, drawn as real jack artwork at a fixed size so
|
|
plates of different heights line up. Power outlets are artwork only — they are
|
|
never a cable endpoint.
|
|
|
|
Patch-facing gear (switches, patch panels) shows its ports permanently;
|
|
everything else reveals them on hover, on selection, or when cables are shown.
|
|
|
|
To cable:
|
|
|
|
1. Click **Patch** in the header.
|
|
2. **Drag from one port to another** — a dashed rubber band follows the pointer.
|
|
Clicking the two ports in turn works just as well. **Escape** drops a
|
|
half-drawn patch.
|
|
3. Repeat. One cable per port; copper or fibre follows the port you start from.
|
|
4. Click **Exit patching** when done — the canvas returns to the cable visibility
|
|
it had before.
|
|
|
|
To unplug: **click the cable** (it gets an accent halo), then press
|
|
**Delete/Backspace** or click **Unplug** in the header. A stray click never
|
|
destroys a patch.
|
|
|
|
A header select controls what you see: cables **on hover**, **always**, or
|
|
**hidden**. Cables
|
|
pan and zoom with the canvas and may run from one rack to another. A cable you
|
|
have selected stays drawn whatever that select says.
|
|
|
|
### Documenting a cable
|
|
|
|
**Click a cable** — patching or not — and a panel opens on the right:
|
|
|
|
| Field | What it does |
|
|
|---|---|
|
|
| Endpoints | The two devices and ports the run connects. Read-only: move a patch by unplugging it and drawing it again. |
|
|
| Type | Ethernet or fibre. A cable still wearing its type's default colour is recoloured to match; a colour you picked yourself is kept. |
|
|
| Colour | The sheath colours you actually have on the shelf, plus a free hex field for anything else. |
|
|
| Label | A name for the run — "Uplink to core", a patch-panel reference. **Show on canvas** prints it next to the cable. |
|
|
| Properties | Anything else worth recording: length, VLAN, speed, category, patch reference. Same editor as a node's properties on a diagram — a label, a value, an optional icon, and an eye that decides whether it shows on the canvas. |
|
|
| Unplug cable | Removes the patch. The devices and their ports stay. |
|
|
|
|
What you tick as visible is drawn on a small plate at the middle of the run, so a
|
|
rack photo exports with its cable lengths and VLANs on it. Everything else stays
|
|
in the panel, one click away.
|
|
|
|
### Import links 🔒
|
|
|
|
**Import links** derives patches from the physical links (ethernet, fibre, vlan,
|
|
cluster) already drawn on your diagrams, matching both ends to mounts that point
|
|
at those nodes. Run it as often as you like: a pair of devices already cabled
|
|
is left alone, so a second run after racking more gear only adds what is
|
|
missing.
|
|
|
|
---
|
|
|
|
## Status 🔒
|
|
|
|
A mount's **Status** is either pinned by hand (online / offline / unknown) or set
|
|
to **Check device**: the plate then follows the status check already configured
|
|
on the matching diagram node (ping, HTTP, SSH, …) and its LED lights accordingly.
|
|
|
|
The rack runs no checker of its own — it reads the result of the one your diagram
|
|
already performs. So:
|
|
|
|
- **Check device** is only offered when the mount resolves to a diagram node.
|
|
- Losing that link drops the mount back to `unknown`, rather than leaving it on a
|
|
status nothing answers for.
|
|
- The refresh polls every 60 s, and only while at least one mount is on
|
|
**Check device**.
|
|
|
|
---
|
|
|
|
## Saving
|
|
|
|
Like the diagram canvas, a rack canvas is **saved explicitly** — **Save Rack** in
|
|
the left sidebar, or the header's save button. Nothing is written behind your
|
|
back unless you turn on **Autosave** in Settings.
|
|
|
|
The sidebar footer counts racks, mounts, cables and free U instead of the
|
|
diagram's online/offline tally. **PNG export** works here too.
|
|
|
|
---
|
|
|
|
## Known limits
|
|
|
|
- **Front view only** — no rear view, no half-depth pairing.
|
|
- No 0U side-mounted PDU.
|
|
- No power draw or outlet budgeting.
|
|
- No undo/redo on a rack canvas (the diagram canvas keeps its own).
|
|
- Rack canvases are not shown by the read-only [Live View](../README.md#live-view-read-only-public-canvas).
|
|
- The MCP server exposes diagram nodes and links only, not racks.
|
|
|
|
---
|
|
|
|
## See also
|
|
|
|
- [FEATURES.md](../FEATURES.md) — every feature, one page.
|
|
- [Device Inventory](../FEATURES.md#12-device-inventory-) — where racked devices live.
|
|
- `frontend/src/rack/README.md` — the developer reference for this canvas.
|