Skip to content

Commit 6091035

Browse files
Sbussisoclaude
andcommitted
ui(dashboard): drop redundant Streaming card + manual Refresh button
User confirmed during the dashboard UI review that Active Cameras and Streaming were essentially the same number on the live deployment, and the manual Refresh button was suspect (turned out to be a placebo — loadCameras already fires every 5s on a setInterval). Three small cleanups that move together: 1. Stats grid: drop the Streaming card. Active Cameras stays as "things that aren't down." Total stays. System Status stays. 4 cards → 3. 2. getStats: rewrite the active-count filter to mirror CameraCard's isDown logic — anything NOT in {offline, failed, error, plan-suspended} counts. Old version only matched streaming + online, which silently undercounted any camera in `recording` mode (continuous-24/7) — the count read 0 active even with a camera actively writing to disk. That was a real bug. 3. Camera Feeds section header: remove the manual Refresh button (and the handleRefresh callback, refreshing state, and refreshPlanInfo destructure that fed it). The 5-second auto- refresh interval already keeps the dashboard live; the button was reassuring affordance, not real work. Net diff: ~30 lines removed, 0 added behavior, 1 latent bug fixed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c0aae39 commit 6091035

1 file changed

Lines changed: 22 additions & 24 deletions

File tree

frontend/src/pages/DashboardPage.jsx

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@ function DashboardPage() {
1414
const { getToken } = useAuth()
1515
const { organization, membership } = useOrganization()
1616
const { showToast } = useToasts()
17-
const { planInfo, refreshPlanInfo } = usePlanInfo()
17+
const { planInfo } = usePlanInfo()
1818
const [cameras, setCameras] = useState({})
1919
const [loading, setLoading] = useState(true)
2020
const [error, setError] = useState(null)
2121
const [showUpgrade, setShowUpgrade] = useState(false)
22-
const [refreshing, setRefreshing] = useState(false)
2322
const prevCamerasRef = useRef(null)
2423
const toastedOfflinesRef = useRef(new Set())
2524

@@ -113,21 +112,31 @@ function DashboardPage() {
113112
}, [organization, loadCameras])
114113

115114

116-
const handleRefresh = useCallback(async () => {
117-
setRefreshing(true)
118-
prevCamerasRef.current = null // force state update
119-
await loadCameras()
120-
await refreshPlanInfo()
121-
setRefreshing(false)
122-
}, [loadCameras, refreshPlanInfo])
115+
// No manual refresh handler — the auto-refresh interval above
116+
// (loadCameras every 5s) keeps the dashboard live without user
117+
// action. Manual button was removed once it became clear it was
118+
// a placebo: every Refresh click did the same fetch the background
119+
// poll already runs twice per 10s.
123120

124121
const getStats = () => {
125122
const cameraList = Object.values(cameras)
126-
const active = cameraList.filter(c => c.status === "streaming" || c.status === "online").length
123+
// "Active" = anything that's NOT in a known-down state. Mirrors
124+
// the isDown logic used per-card in CameraCard.jsx so the stat
125+
// count and the per-card UI agree on what "down" means.
126+
// Includes streaming / online / recording / starting / restarting;
127+
// excludes offline / failed / error / plan-suspended. Previous
128+
// version only counted streaming + online and undercounted any
129+
// camera in `recording` mode (continuous-24/7), which a 24/7
130+
// recording camera definitely is — that was a real bug.
131+
const active = cameraList.filter(c =>
132+
!(c.disabled_by_plan ||
133+
c.status === "offline" ||
134+
c.status === "failed" ||
135+
c.status === "error")
136+
).length
127137
const total = cameraList.length
128-
const streaming = cameraList.filter(c => c.status === "streaming").length
129-
const systemOk = Object.keys(cameras).length > 0
130-
return { active, total, streaming, systemOk }
138+
const systemOk = total > 0
139+
return { active, total, systemOk }
131140
}
132141

133142
if (!organization) {
@@ -269,10 +278,6 @@ function DashboardPage() {
269278
<div className="stat-label">Total Cameras</div>
270279
<div className="stat-value blue">{stats.total}</div>
271280
</div>
272-
<div className="stat-card">
273-
<div className="stat-label">Streaming</div>
274-
<div className="stat-value green">{stats.streaming}</div>
275-
</div>
276281
<div className="stat-card">
277282
<div className="stat-label">System Status</div>
278283
<div className={`stat-value ${stats.systemOk ? "green" : "amber"}`}>
@@ -306,13 +311,6 @@ function DashboardPage() {
306311

307312
<div className="section-header">
308313
<h2 className="section-title">Camera Feeds</h2>
309-
<button onClick={handleRefresh} className="btn btn-secondary" disabled={refreshing}>
310-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"
311-
style={refreshing ? { animation: 'spin 0.8s linear infinite' } : {}}>
312-
<path d="M23 4v6h-6M1 20v-6h6M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/>
313-
</svg>
314-
{refreshing ? 'Refreshing...' : 'Refresh'}
315-
</button>
316314
</div>
317315

318316
{loading ? (

0 commit comments

Comments
 (0)