diff --git a/docs/developer/ui-controls.md b/docs/developer/ui-controls.md index 7fba381d..ebda1f07 100644 --- a/docs/developer/ui-controls.md +++ b/docs/developer/ui-controls.md @@ -183,11 +183,11 @@ where: All Books / Podcasts page → toolbar does: Opens the filter drawer for building and applying rules. label: Find device -where: Devices page → Pair a Device +where: Devices page → Add New Device modal does: Looks up the pairing code shown on the registering e-reader and renders the confirm card. label: Pair device -where: Devices page → Pair a Device → confirm card +where: Devices page → Add New Device modal → confirm card does: Binds the device behind the pairing code to the signed-in account. label: Download All diff --git a/templates/devices.templ b/templates/devices.templ index 75e9acfe..970dfceb 100644 --- a/templates/devices.templ +++ b/templates/devices.templ @@ -157,33 +157,6 @@ templ Devices(user User, devices []handlers.DeviceInfo, errorMessage string, bas } -
- On your e-reader, open the Bookhoard sync menu and tap Register device — then enter the - 6-digit code it shows below. Only someone holding the device can see the code, so nobody - else can claim (or interfere with) your registration. -
- - -On your e-reader, open the Bookhoard sync menu and tap Register device — then enter the 6-digit code it shows below. Only someone holding the device can see the code, so nobody else can claim (or interfere with) your registration.
plugins/ directory")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "KOReader Plugin Setup- 1 Clone the Bookhoard plugin to your KOReader
plugins/ directory - 2 Open KOReader, tap the wrench icon at the top
- 3 Find and tap Bookhoard sync
- 4 Tap Server URL, enter your server address, then tap OK:
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(baseURL)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `devices.templ`, Line: 221, Col: 148}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `devices.templ`, Line: 194, Col: 148}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, " - 5 Tap Register device — your e-reader shows a 6-digit pairing code.
- 6 Type that code into the Pair a Device field on this page and confirm — the device finishes connecting by itself.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "- 5 Tap Register device — your e-reader shows a 6-digit pairing code.
- 6 Enter the code below and click Find device, then confirm on the card that appears — the device finishes connecting by itself.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -552,7 +552,7 @@ func PairingLookupResult(deviceName string, deviceType string, pairingCode strin
var templ_7745c5c3_Var20 string
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(deviceName)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `devices.templ`, Line: 462, Col: 84}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `devices.templ`, Line: 454, Col: 84}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
if templ_7745c5c3_Err != nil {
@@ -565,7 +565,7 @@ func PairingLookupResult(deviceName string, deviceType string, pairingCode strin
var templ_7745c5c3_Var21 string
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(deviceType)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `devices.templ`, Line: 464, Col: 17}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `devices.templ`, Line: 456, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
if templ_7745c5c3_Err != nil {
@@ -578,7 +578,7 @@ func PairingLookupResult(deviceName string, deviceType string, pairingCode strin
var templ_7745c5c3_Var22 string
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.ResolveAttributeValue(pairingCode)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `devices.templ`, Line: 468, Col: 64}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `devices.templ`, Line: 460, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var22)
if templ_7745c5c3_Err != nil {
diff --git a/tests/ui/COVERAGE.md b/tests/ui/COVERAGE.md
index f4748882..9f158182 100644
--- a/tests/ui/COVERAGE.md
+++ b/tests/ui/COVERAGE.md
@@ -28,7 +28,7 @@ Gate: every line below executes for BOTH personas unless marked
| 21 | Podcasts: cross-user invisibility — own feed only (RLS §20 surfaces) | 🔲 | 🔲 |
| 22 | Podcasts: order selector re-renders episode list; serial suggestion shown only for serial/audiobook feeds | 🔲 | 🔲 |
| 23 | Podcasts: audio reader "Ep N/M" + prev/next episode; chain-advance to next episode | 🔲 | 🔲 |
-| 24 | Devices: Pair a Device — code lookup renders templ confirm card, claim binds + page refresh; wrong/expired code renders inline error partial (not a toast-only path) | 🔲 | 🔲 (registration invisible by design) |
+| 24 | Devices: Add New Device modal — pairing-code lookup renders templ confirm card in the modal, claim binds + page refresh; wrong/expired code renders inline error partial (not a toast-only path) | 🔲 | 🔲 (registration invisible by design) |
### Podcast-specific sweep notes (plan task 1.10)
diff --git a/web/src/device-management.ts b/web/src/device-management.ts
index b465fdb5..d9c5712e 100644
--- a/web/src/device-management.ts
+++ b/web/src/device-management.ts
@@ -463,13 +463,13 @@ function setupEventDelegation(): void {
}
});
- // Pairing section: htmx only swaps 2xx bodies, so claim/lookup failures
- // (wrong code, rate limit, expired) would otherwise fail silently.
- // Content-level answers come from the templ partial; this toast covers
- // the non-swap error path.
+ // Pairing (Add Device modal): htmx only swaps 2xx bodies, so claim/lookup
+ // failures (wrong code, rate limit, expired) would otherwise fail
+ // silently. Content-level answers come from the templ partial; this
+ // toast covers the non-swap error path.
document.body.addEventListener("htmx:responseError", (e) => {
const detail = (e as CustomEvent<{ requestConfig?: { elt?: Element } }>).detail;
- if (detail?.requestConfig?.elt?.closest("#pairing-section")) {
+ if (detail?.requestConfig?.elt?.closest("#add-device-modal")) {
showToast("Pairing failed — check the code and try again.", "error");
}
});