Skip to content

Commit 6d97d93

Browse files
committed
test build: Windows NFC hot-plug fix (+ in-progress v1.10.30 work)
Test branch to produce an unsigned Windows installer for on-device testing of the ACR122U/TigerPOD hot-plug fix on Windows. Main fix under test: - services/nfc-process.js — win32 watchdog re-establishes the PC/SC context when the reader monitor errors out (SCardSvr trigger-start), so readers plugged in after launch are detected without a restart. Also bundles the rest of the in-progress v1.10.30 work (toolbox surgical refresh + shared _wireToolbox, detail "Type de tag" badge + row reorder, notifications auto-close on opening a side card, twin-link preservation on single-chip scan) and the test-build-win workflow.
1 parent a2906db commit 6d97d93

9 files changed

Lines changed: 441 additions & 319 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Test build (Windows)
2+
3+
# On-demand Windows build for sharing a test .exe with a tester (e.g. the NFC
4+
# hot-plug fix), WITHOUT cutting a release. The installer is uploaded as a
5+
# workflow artifact — no git tag, no GitHub Release, no auto-update. The .exe is
6+
# UNSIGNED (Windows SmartScreen will warn → "More info" → "Run anyway").
7+
#
8+
# Two ways to run it:
9+
# • push any branch named test/** (this file must be on that branch)
10+
# • Actions tab → "Test build (Windows)" → Run workflow (once it's on main)
11+
#
12+
# Native module note: nfc-pcsc is a C++ addon, so the build MUST run on a real
13+
# Windows runner — it cannot be cross-compiled from macOS.
14+
15+
on:
16+
push:
17+
branches:
18+
- 'test/**'
19+
workflow_dispatch: {}
20+
21+
permissions:
22+
contents: read
23+
24+
jobs:
25+
build-win:
26+
runs-on: windows-latest
27+
steps:
28+
- uses: actions/checkout@v5
29+
30+
- uses: actions/setup-node@v5
31+
with:
32+
node-version: 24
33+
34+
- run: npm ci
35+
36+
- name: Build Windows installer (unsigned, no publish)
37+
run: npm run build:win:nopublish
38+
env:
39+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40+
# Baked in so Google sign-in works in the test build.
41+
TIGERTAG_GOOGLE_DESKTOP_CLIENT_ID: ${{ secrets.TIGERTAG_GOOGLE_DESKTOP_CLIENT_ID }}
42+
TIGERTAG_GOOGLE_DESKTOP_CLIENT_SECRET: ${{ secrets.TIGERTAG_GOOGLE_DESKTOP_CLIENT_SECRET }}
43+
44+
- name: Upload installer artifact
45+
uses: actions/upload-artifact@v4
46+
with:
47+
name: TigerStudio-Windows-test
48+
path: dist/*.exe
49+
if-no-files-found: error
50+
retention-days: 14

‎CLAUDE.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,19 @@ Lazy ping: on `mouseenter`, fires one `fetch` to `/healthz/` and updates the too
320320
### Weight slider auto-save
321321
The weight slider in the detail panel debounces writes to Firestore: after **500 ms of inactivity** the value is committed automatically. The fill bar pulses (`.wb-saving` class) during the debounce window. Clicking "Update" cancels the pending debounce and saves immediately. Closing the panel cancels any pending save.
322322

323+
### Surgical DOM updates — patch the smallest unit, never rebuild the world
324+
**Default reflex when something changes: re-render only the sub-element that actually changed, not the whole panel / modal / view.** Blowing away a container's `innerHTML` to reflect a small change is the recurring bug source here — it **reloads `<img>`/`<video>` (media flashes / restarts), drops scroll + focus + text selection, cancels an in-progress hold-to-confirm or inline edit, and re-runs every wiring**. If only the toolbox buttons flip, only the toolbox should update.
325+
326+
**Decision procedure (cheapest first):**
327+
1. **Guard with a signature** — compute a small string/tuple of *what the render depends on*; bail early when it's unchanged so nothing re-renders on a no-op event. (`_rowSignature`, `_detailStructuralSig`, `_panelCardSig`.)
328+
2. **Patch in place** when a scalar/class changed — set `textContent`/`style`/`classList` on the exact node, no HTML rebuild. (`_patchDetailWeight`, `_patchCamWall`.)
329+
3. **Swap one section** when a whole sub-block changed — regenerate the panel HTML *off-DOM* (`const tmp = document.createElement('div'); tmp.innerHTML = buildPanelHTML(r)`), lift out just that section (`tmp.querySelector('.panel-section--toolbox')`), `replaceWith` it into the live DOM, then re-wire **only** that section.
330+
4. **Full rebuild** (`innerHTML = buildX()`) is the LAST resort — only when the structural signature genuinely changed; even then preserve live media (`_rebuildDetailKeepVideo`).
331+
332+
**To make a section independently swappable, split its render from its wiring** into paired functions and call the wirer from both the initial render and the surgical refresh (canonical example: `buildPanelHTML` renders the `.panel-section--toolbox`, `_wireToolbox(r)` wires it; `openDetail` calls both, `_maybeRefreshPanelForCard` swaps just the toolbox node + calls `_wireToolbox`). Keep delegated handlers on the stable parent (`#panelBody`) so children swapped underneath keep working without re-wiring (the ⓘ tips via `_wireToolInfoTips`).
333+
334+
**Smell test before a rebuild:** does this change touch media, scroll, focus, an in-progress gesture, or 90% unchanged markup? If yes, find the smallest node that changed and patch/swap that instead.
335+
323336
### State
324337
```js
325338
state = {

‎WORKLOG.md‎

Lines changed: 11 additions & 19 deletions
Large diffs are not rendered by default.

‎package-lock.json‎

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tigertag-inventory",
3-
"version": "1.10.29",
3+
"version": "1.10.30",
44
"description": "Tiger Studio Manager — desktop app",
55
"main": "main.js",
66
"engines": {

‎renderer/CODEMAP.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ Manual spool creation: full chip-schema editor with bottom-sheets. All helpers p
231231

232232
---
233233

234-
## Spool detail panel (L7480-9804)
234+
## Spool detail panel (L7480-9990)
235235

236236
| L | What | Anchors |
237237
|---|---|---|
@@ -247,7 +247,7 @@ Manual spool creation: full chip-schema editor with bottom-sheets. All helpers p
247247

248248
---
249249

250-
## Panels / debug / auto-update (L9372-10601)
250+
## Panels / debug / auto-update (L9372-10800)
251251

252252
| L | What | Anchors |
253253
|---|---|---|
@@ -341,7 +341,7 @@ Per-brand scan/manual flows live in `printers/<brand>/add-flow.js`; `inventory.j
341341

342342
---
343343

344-
## Friend view (L16951-17844)
344+
## Friend view (L16951-18030)
345345

346346
| L | What | Anchors |
347347
|---|---|---|
@@ -352,7 +352,7 @@ Per-brand scan/manual flows live in `printers/<brand>/add-flow.js`; `inventory.j
352352

353353
---
354354

355-
## Display name + friend requests (L17523-18560)
355+
## Display name + friend requests (L17523-18760)
356356

357357
| L | What | Anchors |
358358
|---|---|---|

‎renderer/css/70-detail-misc.css‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,9 @@
12581258
.panel-row { display: flex; justify-content: space-between; align-items: center; font-size: 13px; margin-bottom: 5px; }
12591259
.panel-row .pk { color: var(--muted); }
12601260
.panel-row .pv { font-weight: 500; text-align: right; max-width: 60%; }
1261+
/* Badge-valued row (e.g. "Type de tag" → tier badge + backup shield) — align
1262+
the pill to the right, vertically centred with the key. */
1263+
.panel-row .pv-badge { display: inline-flex; align-items: center; gap: 4px; }
12611264
.panel-row .pv a { color: var(--primary); text-decoration: none; }
12621265
.panel-row .pv a:hover { text-decoration: underline; }
12631266
/* Value cell that is itself a link (e.g. Product ID → tigertag.io). */
@@ -2087,6 +2090,18 @@
20872090
}
20882091
.toolbox-row--inert:active { transform: none; }
20892092

2093+
/* Greyed-out look for a device-gated tool that isn't usable yet — desaturated
2094+
+ dimmed so it reads as unavailable, but STILL clickable. The click either
2095+
opens the TigerPOD promo (reader-gated chip tools, +.toolbox-row--pod-lock)
2096+
or the device's own connect modal (TD1S measure tools — unchanged). The
2097+
grayscale neutralises the row's variant colour (danger red / primary orange
2098+
→ grey). Also used on the main button of a split row. */
2099+
.toolbox-row--greyed {
2100+
filter: grayscale(1);
2101+
opacity: .5;
2102+
}
2103+
.toolbox-row--greyed:hover { opacity: .7; }
2104+
20902105
/* Split rows: a flex wrapper containing a main <button> + a trailing
20912106
<button>. The wrapper itself is not interactive — each child handles
20922107
its own hover / hold state independently. */

0 commit comments

Comments
 (0)