Skip to content

Commit b9db373

Browse files
committed
v0.2.9: fix tab-switch render race (unknown faces could appear under the Ignored tab)
1 parent b19f4dd commit b9db373

5 files changed

Lines changed: 27 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
All notable changes to FaceID. The Home Assistant add-on shows this file in the
44
update dialog; standalone users can watch GitHub releases.
55

6+
## 0.2.9 — 2026-07-23
7+
8+
- **Fix: tab content race** — switching tabs while a fetch was still in flight
9+
could let the finishing request overwrite the newly opened tab (e.g. freshly
10+
detected unknown faces appeared under the Ignored tab). Each view now only
11+
renders if its tab is still active.
12+
613
## 0.2.8 — 2026-07-22
714

815
- **Fix: fresh installs and updates crashed on start** (`ImportError:

faceid-addon/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
All notable changes to FaceID. The Home Assistant add-on shows this file in the
44
update dialog; standalone users can watch GitHub releases.
55

6+
## 0.2.9 — 2026-07-23
7+
8+
- **Fix: tab content race** — switching tabs while a fetch was still in flight
9+
could let the finishing request overwrite the newly opened tab (e.g. freshly
10+
detected unknown faces appeared under the Ignored tab). Each view now only
11+
renders if its tab is still active.
12+
613
## 0.2.8 — 2026-07-22
714

815
- **Fix: fresh installs and updates crashed on start** (`ImportError:

faceid-addon/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: FaceID
2-
version: "0.2.8"
2+
version: "0.2.9"
33
slug: faceid
44
description: Face recognition for Frigate — trainable gallery, clustered unknown review, HA sensors
55
url: https://github.com/SkyTechNerds/faceid

faceid-addon/static/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ <h1>FACEID</h1>
100100
function personOptions(){return Object.entries(persons).map(([s,p])=>`<option value="${s}">${esc(p.name)}</option>`).join('')}
101101

102102
async function render(){
103+
const t=tab;
103104
persons=await j('api/persons');
105+
if(t!==tab)return;
104106
if(tab==='unknowns')return renderUnknowns();
105107
if(tab==='persons')return renderPersons();
106108
if(tab==='ignored')return renderIgnored();
@@ -136,6 +138,7 @@ <h1>FACEID</h1>
136138
}
137139
async function renderUnknowns(){
138140
const [clusters,bf]=await Promise.all([j('api/unknowns'),j('api/backfill')]);
141+
if(tab!=='unknowns')return;
139142
if(bf.running&&tab==='unknowns')setTimeout(()=>{if(tab==='unknowns')render()},4000);
140143
if(!clusters.length){
141144
main.innerHTML=backfillRow(bf)+'<div class="empty">No unknown faces in the queue.</div>';return}
@@ -167,6 +170,7 @@ <h1>FACEID</h1>
167170
}
168171
async function renderIgnored(){
169172
const clusters=await j('api/ignored');
173+
if(tab!=='ignored')return;
170174
if(!clusters.length){main.innerHTML='<div class="empty">Nobody on the ignore list. Use "ignore" on an unknown cluster or "ignore person" on a person card — ignored people are never notified, matched or resurfaced.</div>';return}
171175
const total=clusters.reduce((a,c)=>a+c.length,0);
172176
main.innerHTML=`<div class="row"><span class="stat">${total} anchor face(s) in ${clusters.length} group(s) — never notified, never matched to a known person, never resurfaced.</span></div>`
@@ -278,6 +282,7 @@ <h1>FACEID</h1>
278282
}
279283

280284
async function renderPersons(){
285+
if(tab!=='persons')return;
281286
const entries=Object.entries(persons);
282287
main.innerHTML=`
283288
<div class="row">
@@ -324,6 +329,7 @@ <h1>FACEID</h1>
324329

325330
async function renderRecent(){
326331
const rows=await j('api/recent');
332+
if(tab!=='recent')return;
327333
main.innerHTML=rows.length?`<table>
328334
<tr><th>Time</th><th>Camera</th><th>Person</th><th>Score</th><th>Event</th></tr>
329335
${rows.map(r=>`<tr><td>${fmtTs(r.ts)}</td><td>${esc(r.camera)}</td>

static/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ <h1>FACEID</h1>
100100
function personOptions(){return Object.entries(persons).map(([s,p])=>`<option value="${s}">${esc(p.name)}</option>`).join('')}
101101

102102
async function render(){
103+
const t=tab;
103104
persons=await j('api/persons');
105+
if(t!==tab)return;
104106
if(tab==='unknowns')return renderUnknowns();
105107
if(tab==='persons')return renderPersons();
106108
if(tab==='ignored')return renderIgnored();
@@ -136,6 +138,7 @@ <h1>FACEID</h1>
136138
}
137139
async function renderUnknowns(){
138140
const [clusters,bf]=await Promise.all([j('api/unknowns'),j('api/backfill')]);
141+
if(tab!=='unknowns')return;
139142
if(bf.running&&tab==='unknowns')setTimeout(()=>{if(tab==='unknowns')render()},4000);
140143
if(!clusters.length){
141144
main.innerHTML=backfillRow(bf)+'<div class="empty">No unknown faces in the queue.</div>';return}
@@ -167,6 +170,7 @@ <h1>FACEID</h1>
167170
}
168171
async function renderIgnored(){
169172
const clusters=await j('api/ignored');
173+
if(tab!=='ignored')return;
170174
if(!clusters.length){main.innerHTML='<div class="empty">Nobody on the ignore list. Use "ignore" on an unknown cluster or "ignore person" on a person card — ignored people are never notified, matched or resurfaced.</div>';return}
171175
const total=clusters.reduce((a,c)=>a+c.length,0);
172176
main.innerHTML=`<div class="row"><span class="stat">${total} anchor face(s) in ${clusters.length} group(s) — never notified, never matched to a known person, never resurfaced.</span></div>`
@@ -278,6 +282,7 @@ <h1>FACEID</h1>
278282
}
279283

280284
async function renderPersons(){
285+
if(tab!=='persons')return;
281286
const entries=Object.entries(persons);
282287
main.innerHTML=`
283288
<div class="row">
@@ -324,6 +329,7 @@ <h1>FACEID</h1>
324329

325330
async function renderRecent(){
326331
const rows=await j('api/recent');
332+
if(tab!=='recent')return;
327333
main.innerHTML=rows.length?`<table>
328334
<tr><th>Time</th><th>Camera</th><th>Person</th><th>Score</th><th>Event</th></tr>
329335
${rows.map(r=>`<tr><td>${fmtTs(r.ts)}</td><td>${esc(r.camera)}</td>

0 commit comments

Comments
 (0)