With a linked record, it opens the device's record in the inventory.
Without one, it searches the inventory for the device's model.
Admins set or clear the link with ✎ by pasting the record's URL. Only https:// URLs on inventory.base_url are accepted, which rules out other hosts, lookalike hosts, embedded credentials and javascript: URLs, since the link is shown to every viewer.
Links are stored in a new device_links table, created alongside the cutsheet tables.
PUT /api/device/<name>/inventory requires admin rights and a JSON body.
Tickets now include the inventory link when one is set.
Cutsheet marks on faceplates. A port with a documented cable gets a corner dot:
green: it matches what Gandalf sees
red: a mismatch (wrong neighbor, no link, missing port, or port conflict)
grey: documented but not confirmable (planned, dark, through a panel, or the far end isn't visible)
Hovering a port names the cable and the check result. The legend shows a key for the dots plus a "Cutsheet marks" checkbox that hides them; the browser remembers the choice. The data comes from what /api/device already returns, so no new API calls are made.
Page titles.base.html already appended "— GANDALF", and every page added "– GANDALF" again, so tabs read "Alert History – GANDALF — GANDALF". Each title now has the name once, and a test covers it.
Config:inventory.base_url (default https://inventory.lotusguild.org) and inventory.search_url (default {base}/items?q={q}). I couldn't confirm HomeBox's search route from here because it's behind Authelia. If "Find in inventory" opens the wrong page, set inventory.search_url.
Testing
Automated: 339 tests pass (14 new). They cover the inventory link's validation and auth, the configured host, the device API fields, the ticket link, and the page titles.
Local MariaDB:device_links table creation can run twice safely. Insert, update and clear all work.
Playwright:
The page shows 6 marks: 1 green, 2 red and 3 grey, as expected for the seeded cables.
The port tooltip names the cable.
The marks toggle survives a reload.
A bad URL is rejected with a clear message.
Removing a link switches the button to "Find in inventory", and saving one switches it back.
The phone header fits at 390 px.
flake8 and bandit are clean, and ESLint reports 0 errors.
## What changes
**Inventory links.** Device pages get a 📦 button:
- With a linked record, it opens the device's record in the inventory.
- Without one, it searches the inventory for the device's model.
- Admins set or clear the link with ✎ by pasting the record's URL. Only `https://` URLs on `inventory.base_url` are accepted, which rules out other hosts, lookalike hosts, embedded credentials and `javascript:` URLs, since the link is shown to every viewer.
- Links are stored in a new `device_links` table, created alongside the cutsheet tables.
- `PUT /api/device/<name>/inventory` requires admin rights and a JSON body.
- Tickets now include the inventory link when one is set.
**Cutsheet marks on faceplates.** A port with a documented cable gets a corner dot:
- **green**: it matches what Gandalf sees
- **red**: a mismatch (wrong neighbor, no link, missing port, or port conflict)
- **grey**: documented but not confirmable (planned, dark, through a panel, or the far end isn't visible)
Hovering a port names the cable and the check result. The legend shows a key for the dots plus a "Cutsheet marks" checkbox that hides them; the browser remembers the choice. The data comes from what `/api/device` already returns, so no new API calls are made.
**Page titles.** `base.html` already appended "— GANDALF", and every page added "– GANDALF" again, so tabs read "Alert History – GANDALF — GANDALF". Each title now has the name once, and a test covers it.
**Config:** `inventory.base_url` (default `https://inventory.lotusguild.org`) and `inventory.search_url` (default `{base}/items?q={q}`). I couldn't confirm HomeBox's search route from here because it's behind Authelia. If "Find in inventory" opens the wrong page, set `inventory.search_url`.
## Testing
- **Automated:** 339 tests pass (14 new). They cover the inventory link's validation and auth, the configured host, the device API fields, the ticket link, and the page titles.
- **Local MariaDB:** `device_links` table creation can run twice safely. Insert, update and clear all work.
- **Playwright:**
- The page shows 6 marks: 1 green, 2 red and 3 grey, as expected for the seeded cables.
- The port tooltip names the cable.
- The marks toggle survives a reload.
- A bad URL is rejected with a clear message.
- Removing a link switches the button to "Find in inventory", and saving one switches it back.
- The phone header fits at 390 px.
- flake8 and bandit are clean, and ESLint reports 0 errors.
Screenshots are in the comments.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Device pages get an Inventory button: it opens the device's HomeBox record
once an admin pastes its URL (stored in the new device_links table; only
URLs on inventory.base_url are accepted), and searches the inventory for
the model until then. Tickets link the record too.
Faceplate ports with a documented cable get a corner dot: green matches,
red mismatch, grey documented but unconfirmed. The port's tooltip names
the cable, and a legend toggle (remembered per browser) hides them.
Page titles no longer repeat GANDALF ("Alert History - GANDALF - GANDALF").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Faceplate with cutsheet marks. Port 9 is green: its documented cable matches. Ports 10 and 12 are red: on 12 a different host is plugged in, and on 10 the planned device isn't linked. Ports 3, 6 and 15 are grey: two run through the patch panel to wall jacks, and one is still planned. The legend has the key and the toggle.
Device header with a linked inventory record. The ✎ button is admin-only.
Inventory link editor, after trying a URL on another host, which was rejected.
Phone (390 px).
## Screenshots (local preview, sample data)
**Faceplate with cutsheet marks.** Port 9 is green: its documented cable matches. Ports 10 and 12 are red: on 12 a different host is plugged in, and on 10 the planned device isn't linked. Ports 3, 6 and 15 are grey: two run through the patch panel to wall jacks, and one is still planned. The legend has the key and the toggle.

**Device header with a linked inventory record.** The ✎ button is admin-only.

**Inventory link editor**, after trying a URL on another host, which was rejected.

**Phone (390 px).**

jared
merged commit ee2708dccb into main2026-11-10 20:50:27 -05:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What changes
Inventory links. Device pages get a 📦 button:
https://URLs oninventory.base_urlare accepted, which rules out other hosts, lookalike hosts, embedded credentials andjavascript:URLs, since the link is shown to every viewer.device_linkstable, created alongside the cutsheet tables.PUT /api/device/<name>/inventoryrequires admin rights and a JSON body.Cutsheet marks on faceplates. A port with a documented cable gets a corner dot:
Hovering a port names the cable and the check result. The legend shows a key for the dots plus a "Cutsheet marks" checkbox that hides them; the browser remembers the choice. The data comes from what
/api/devicealready returns, so no new API calls are made.Page titles.
base.htmlalready appended "— GANDALF", and every page added "– GANDALF" again, so tabs read "Alert History – GANDALF — GANDALF". Each title now has the name once, and a test covers it.Config:
inventory.base_url(defaulthttps://inventory.lotusguild.org) andinventory.search_url(default{base}/items?q={q}). I couldn't confirm HomeBox's search route from here because it's behind Authelia. If "Find in inventory" opens the wrong page, setinventory.search_url.Testing
device_linkstable creation can run twice safely. Insert, update and clear all work.Screenshots are in the comments.
🤖 Generated with Claude Code
Device pages get an Inventory button: it opens the device's HomeBox record once an admin pastes its URL (stored in the new device_links table; only URLs on inventory.base_url are accepted), and searches the inventory for the model until then. Tickets link the record too. Faceplate ports with a documented cable get a corner dot: green matches, red mismatch, grey documented but unconfirmed. The port's tooltip names the cable, and a legend toggle (remembered per browser) hides them. Page titles no longer repeat GANDALF ("Alert History - GANDALF - GANDALF"). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Screenshots (local preview, sample data)
Faceplate with cutsheet marks. Port 9 is green: its documented cable matches. Ports 10 and 12 are red: on 12 a different host is plugged in, and on 10 the planned device isn't linked. Ports 3, 6 and 15 are grey: two run through the patch panel to wall jacks, and one is still planned. The legend has the key and the toggle.
Device header with a linked inventory record. The ✎ button is admin-only.
Inventory link editor, after trying a URL on another host, which was rejected.
Phone (390 px).