Skip to content

feat: add search/filter to sidebar tabs#83

Merged
cyyeh merged 1 commit into
mainfrom
feat/sidebar-search-filter
Mar 2, 2026
Merged

feat: add search/filter to sidebar tabs#83
cyyeh merged 1 commit into
mainfrom
feat/sidebar-search-filter

Conversation

@cyyeh
Copy link
Copy Markdown
Owner

@cyyeh cyyeh commented Mar 2, 2026

Summary

  • Add a magnifying glass toggle button to each sidebar tab (Tables, Skills, Memories) that reveals a filter input
  • Tables filter by name, Skills by name and description, Memories by content
  • All filtering is case-insensitive substring matching
  • Includes i18n support for both English and Chinese (6 new keys)

Test plan

  • Switch between all 3 tabs, verify search icon appears
  • Click search icon to toggle input open/close, verify filter clears on close
  • Type in filter input, verify items filter correctly
  • Test in both English and Chinese locales

🤖 Generated with Claude Code

Add a magnifying glass toggle button to each sidebar tab that reveals
a filter input for quick case-insensitive substring search. Tables
filter by name, Skills by name and description, and Memories by content.
Includes i18n support for both English and Chinese.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: d857032b6158
@cyyeh cyyeh merged commit 9f01a8d into main Mar 2, 2026
2 checks passed
@cyyeh cyyeh deleted the feat/sidebar-search-filter branch March 2, 2026 02:22
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 2, 2026

Claude finished @cyyeh's task in 1m 32s —— View job


Code Review: feat/sidebar-search-filter

Overall this is a clean, well-structured implementation. The feature works correctly and follows existing patterns in the codebase. A few items worth noting:


✅ Strengths

  • Correct useMemo usage: All three filtering implementations (filteredTables, filteredSkills, filteredEntries) correctly memoize derived state, avoiding unnecessary recomputation on unrelated re-renders.
  • Good i18n coverage: 6 translation keys added consistently in both en.json and zh-TW.json, with proper Unicode escaping for the ellipsis character (\u2026).
  • Clean UX pattern: Toggle-to-reveal search with auto-clear on close is a sensible pattern. autoFocus on the input makes the interaction smooth.
  • Security: No vulnerabilities introduced. Filtering is purely client-side on already-loaded data, and React's controlled inputs prevent XSS.

🟡 Issues Worth Addressing

1. Significant CSS Duplication

The action button and search input styles are copy-pasted identically across three CSS files:

Style block Files
__action-btn, __action-btn--active Sidebar.css, SkillsPanel.css, MemoriesPanel.css
__search-input + :focus Sidebar.css, SkillsPanel.css, MemoriesPanel.css

Each duplicated block is ~15–20 lines. Consider extracting these into shared utility classes (e.g., in App.css) like .action-btn--active and .panel-search-input. Fix this →

2. No "No Results Found" State in SkillsPanel

When the filter matches nothing in SkillsPanel, the <ul> renders empty with no message. In contrast, MemoriesPanel shows category-level empty states (but these say "No X saved yet" — which is misleading when items exist but are filtered). Fix this →

// SkillsPanel.tsx — after filteredSkills.map(...)
{filteredSkills.length === 0 && searchTerm && (
  <p className="skills-panel__empty">{t('noSearchResults')}</p>
)}

3. SkillsPanel Early Return Hides Search Button

SkillsPanel.tsx:87-98 — when skills.length === 0, the component returns early showing only the create + button. This is consistent UX (no point searching empty data), but it diverges from the Tables tab behavior where the search icon is always visible. Document this intent or align the behavior:

// Current: early return skips search button entirely
if (skills.length === 0) {
  return (
    <div className="skills-panel">
      <div className="skills-panel__actions">
        <button className="skills-panel__create-btn" ...>+</button>
        {/* search button absent */}
      </div>
      ...
    </div>
  );
}

4. Search State Persists Across Tab Switches

Search open/closed state and the search term are stored in component state for SkillsPanel and MemoriesPanel (and in Sidebar state for Tables). These states survive tab switches — switching away and back keeps the search open with the previous term. Whether intentional or not, this behavior should be consistent. Currently the Tables tab clears search on toggle-close but not on tab switch.

5. Missing Escape Key Handler

None of the search inputs close on Escape keydown. This is a minor accessibility/UX gap. Fix this →

onKeyDown={(e) => { if (e.key === 'Escape') { setTableSearchOpen(false); setTableSearch(''); } }}

🔵 Minor Notes

  • MemoriesPanel.tsx:120key={${group.category}-${idx}} uses array index. Since entry.content is unique, it could serve as a more stable key, though for static lists this is low-risk.
  • No tests added — consistent with the rest of the frontend (no existing tests visible), but the filtering logic (useMemo callbacks) would be trivial to unit-test.
  • Other CSS files modified (e.g., App.css, ChatInput.css, MessageBubble.css) — these appear to be unrelated CSS additions not directly connected to the search feature. If they were part of a batch cleanup it would help to note that in the PR description.

Summary

The core feature is solid and production-ready. The main follow-up candidates are: CSS deduplication (maintainability) and filtered-empty states (UX clarity). No security or correctness issues found.

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.

1 participant