Skip to content

fix(webui): keep sandbox state counts across filters#961

Open
zyl1121 wants to merge 1 commit into
TencentCloud:masterfrom
zyl1121:fix/webui-sandbox-filter-count
Open

fix(webui): keep sandbox state counts across filters#961
zyl1121 wants to merge 1 commit into
TencentCloud:masterfrom
zyl1121:fix/webui-sandbox-filter-count

Conversation

@zyl1121

@zyl1121 zyl1121 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Background

On the WebUI sandbox page, selecting the Running tab could make the Paused badge count disappear even when paused sandboxes still existed.

The page requested a state-filtered sandbox list and then calculated all status badge counts from that already-filtered response. As a result, switching tabs could make the badge counts reflect only the current tab instead of the full sandbox list.

What Changed

  • Fetch the full sandbox list for the page.
  • Derive the Running and Paused badge counts from the full list.
  • Apply the selected state filter locally to the table rows.
  • Apply text search after the selected state filter.
  • Refetch the full list immediately when switching state tabs, preserving the existing tab-switch refresh behavior.

The state filter is now local because badge counts need the full list. The explicit tab-change refetch is intentional, it preserves the previous immediate-refresh behavior, while the five-second polling interval remains the background refresh mechanism.

Validation

  • npm ci --no-audit --no-fund

  • npm run build

    • includes TypeScript checking and the Vite production build
  • git diff --check

  • Manual validation:

    • ran npm run dev
    • configured the /cubeapi Vite proxy to CubeAPI
    • verified that switching between All, Running, and Paused keeps the paused badge count visible when Running is selected
    • verified that displayed rows still follow the selected state filter

Related

Fixes #960.

@zyl1121 zyl1121 force-pushed the fix/webui-sandbox-filter-count branch from d5b3f0f to 851cddb Compare July 14, 2026 12:00
@cubesandboxbot

Copy link
Copy Markdown

Review: PR #961 – fix(web): keep sandbox state counts across filters

Files changed: 1 · web/src/pages/Sandboxes.tsx (+16 / -8)

Summary

The PR correctly fixes the reported bug (#960). By always fetching the full sandbox list and applying the state filter client-side, badge counts now accurately reflect the full dataset regardless of which tab is active. The implementation is clean and introduces no correctness issues or security concerns.

Positive aspects

  • The useMemo dependency array ([data, q, stateFilter]) is complete — no stale closures.
  • The guard clause if (next === stateFilter) return; prevents no-op updates on tab switch.
  • Empty-state handling (filtered.length === 0 && !isLoading) is correctly placed.
  • The void refetch() idiom correctly suppresses floating-promise lint warnings.

Issues found

1. Redundant refetch() on tab switch (line 37)

Calling void refetch() inside onStateFilterChange is unnecessary. Since:

  • The query key is now ['sandboxes'] (no state filter), and
  • The data is already polled every 5 seconds via refetchInterval: 5_000,

every tab switch fires an extra HTTP request for data that is already present and at most 5 seconds stale in the cache. For users who toggle between Running and Paused tabs, this multiplies backend load for zero data benefit.

Recommendation: Remove the void refetch(); call. The filter is entirely client-side now, so tab switching is purely a UI state change.

2. Inline badge counts recompute redundant O(n) passes (line 140)

{data.filter((sb) => (sb.state ?? 'running') === key).length}

This filter runs on every render — once for the Running badge and once for the Paused badge — producing two full passes over data on each render cycle. Meanwhile, the filtered useMemo (line 66) is already doing a similar operation. For deployments with many sandboxes or the 5-second polling interval, this adds unnecessary render-time CPU cost.

Recommendation: Derive badge counts inside the existing useMemo alongside filtered to reduce render-phase work from 3 passes to 1 pass.

3. Duplicated sb.state ?? 'running' default

The state-defaulting expression sb.state ?? 'running' appears in three places (lines 70, 140, 198). If the default or valid states ever change, all three must be updated in lockstep.

Recommendation: Extract a small helper (e.g. const sandboxState = (sb: RunningSandbox) => sb.state ?? 'running') to centralize the default.

Test coverage

The web frontend has no test infrastructure — no test runner, no test files, no test script. This PR fixes a bug that would have been caught by a simple unit test on the filtering pipeline (data → stateFilter → search query → filtered rows). Adding test coverage for the filtering and badge count logic would prevent similar regressions. However, this is a project-level gap, not a concern specific to this PR.

Security

No security issues were identified — all data flows through proper authentication headers, all user-visible content is React-escaped, and no new attack surface is created. Safe to merge from a security perspective.

Verdict

The fix is correct and addresses the root cause. The two actionable suggestions are:

  1. Recommended before merge: Remove the redundant refetch() on tab switch (line 37).
  2. Nice to have: Memoize badge counts to avoid redundant O(n) passes (line 140).

Merging as-is would not introduce a regression.

Comment thread web/src/pages/Sandboxes.tsx
@zyl1121 zyl1121 changed the title fix(web): keep sandbox state counts across filters fix(webui): keep sandbox state counts across filters Jul 14, 2026
Fetch the full sandbox list for the page and derive Running and Paused badge counts from that full response.

Apply the selected state tab and text search locally to the displayed table rows, while preserving the immediate refetch behavior on tab changes.

This keeps badge counts visible when switching tabs without backend changes or API contract changes.

Signed-off-by: zhengyilei <zheng_yilei@qq.com>
@zyl1121 zyl1121 force-pushed the fix/webui-sandbox-filter-count branch from 851cddb to b2565f6 Compare July 14, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug Report] a small bug about webui,sandbox show

3 participants