Skip to content

[Bug] Web UI header memory count does not update when filtering by tag - count never matches the filtered list #305

Description

@evilhikari

Summary

On the Web UI page, the memory count in the header (top-right stats) does not update when filtering memories by tag. It always shows the global total from /api/stats regardless of the selected tag, so the number never matches the tag-filtered list shown below it.

The tag-filtered list itself is correct - only the count is wrong/stale.

Steps to reproduce

  1. Open the Web UI (http://127.0.0.1:4747).
  2. Note the header total, e.g. Total: 100.
  3. Select a tag from the tag filter dropdown that matches only a few memories (e.g. a tag with 3 memories).
  4. Observe: the list now shows only the 3 matching memories, but the header still shows Total: 100.
  5. Switch to a different tag - the header number never changes.

Expected behavior

When a tag filter is active, the header count should reflect the filtered result set (the number of memories matching the selected tag) and update when switching tags.

Actual behavior

The header count is always the global /api/stats total. It only changes when a search query is entered, because getDisplayedMemoryCount returns the search total only when isSearching === true. A tag filter is not treated as "searching", so the store total is always shown.

Root cause analysis

The header count is wired to the wrong data source:

  • web/src/lib/memory-count.ts (L1-7) - getDisplayedMemoryCount(isSearching, searchTotal, storeTotal) returns storeTotal whenever not searching: return isSearching ? searchTotal : storeTotal;
  • web/src/App.tsx (L144-157) - header renders getDisplayedMemoryCount(explorer.isSearching, explorer.totalItems, explorer.statsTotal).
  • web/src/hooks/useMemoriesExplorer.ts - loadStats() (L55-60) fetches /api/stats with no tag parameter; onTagFilterChange() (L193-205) reloads the list (loadMemories) but never reloads stats.
  • src/services/api-handlers.ts - handleStats() (L719-756) returns global totals across all project + user shards with no tag awareness: total = userCount + projectCount.
  • handleListMemories() (L150-269) does return a correct filtered total (timeline.length) - but the frontend only uses totalItems when isSearching === true, so the tag-filtered count is discarded.

Secondary inconsistency: handleListTags() (L111-148) only returns project-scoped tags (filters on _project_), while handleStats counts both user and project memories. The displayed "total" can therefore be larger than anything reachable through the tag filter (user-scope memories never appear in the tag dropdown).

Suggested fix direction

Either:

  1. Make the header count tag-aware: pass the selected tag to /api/stats (or return per-tag counts from handleListTags), and display the filtered count when a tag is active; or
  2. Change getDisplayedMemoryCount to return totalItems when a tag filter is active, not only when searching: return isSearching || tagFilterActive ? searchTotal : storeTotal;

Environment

  • OS: Windows
  • opencode-mem: latest (npm v2.25.0)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions