Skip to content

feat: dynamic multi-select source-tool filter - #20

Merged
ClaudiaFang merged 2 commits into
masterfrom
feature/source-tool-multiselect
Jul 21, 2026
Merged

feat: dynamic multi-select source-tool filter#20
ClaudiaFang merged 2 commits into
masterfrom
feature/source-tool-multiselect

Conversation

@ClaudiaFang

Copy link
Copy Markdown
Member

What

Converts the dashboard's "source tool" filter from a hardcoded, single-select dropdown (11 static entries in SourceToolSelect.tsx) to a multi-select control whose options are dynamically derived from what's actually in the SQLite database.

Why

Tools with zero sessions no longer clutter the picker, new source tools appear automatically without a code change, and users can filter by more than one tool at once (e.g. "Claude Code + Cursor").

How

  • Server: added buildInCondition() (TDD, server/src/utils.ts / utils.test.ts) and swapped the four source_tool = ? exact-equality filters (shared-aggregation.ts, sessions.ts, analytics.ts, facets.ts) for source_tool IN (...), built from a comma-split of the incoming query param. A single value still produces an equivalent IN (?) clause, so existing single-value behavior is unchanged. Wire format stays a single CSV string (Zod schemas unchanged) — no new endpoints, consistent with how project/homeId/type filters already work.
  • Dashboard: added useAvailableSourceTools() (dashboard/src/hooks/useFacets.ts), a thin React Query wrapper over the existing fetchFacetAggregation({period:'all'}) -> sourceTools: string[], 5-minute staleTime. Added SourceToolMultiSelect.tsx modeled directly on ProjectMultiSelect.tsx (Popover + Checkbox, value: string[] / onValueChange), self-fetching its option list, using SOURCE_TOOL_DISPLAY_NAMES for labels (falls back to title-case) and a DOT_COLORS map (moved from the old component, falls back to neutral gray for unknown ids).
  • Converted all 5 call sites — InsightsPage, JournalPage, AnalyticsPage, SessionListPanel, ProjectNav (+ SessionsPage as the unchanged parent) — to the repo's existing comma-joined-string filter-state convention (same pattern already used for filters.project), converting to/from string[] only at the component boundary.
  • Deleted SourceToolSelect.tsx and its hardcoded SOURCE_TOOLS array — confirmed via grep no remaining imports.

Schema Impact

  • SQLite schema changed: no
  • Types changed: no (query param semantics changed: source/sourceTool now accept CSV; Zod schemas remain z.string().optional())
  • Server API changed: source/sourceTool filters on /api/sessions, /api/analytics/cache-by-source, /api/facets, /api/facets/aggregated, /api/facets/missing, /api/facets/missing-pq, /api/facets/outdated-pq now accept comma-separated values
  • Backward compatible: yes — single-value CSV behaves identically to today's exact-match

Testing

  • Added TDD tests for buildInCondition() in server/src/utils.test.ts (7 cases, written first and verified failing before implementation)
  • Added CSV-filter test cases alongside each route's existing single-value test (sessions.test.ts, analytics.test.ts, shared-aggregation.test.ts) — existing single-value tests kept and updated only where the where-clause string shape changed (= ? -> IN (?))
  • cd server && pnpm build && pnpm test — 677/677 passing
  • cd dashboard && pnpm build — clean; npx tsc --noEmit — zero errors; pnpm test — 15/15 passing
  • pnpm build && pnpm test from repo root — cli 917/917, dashboard 15/15, server 677/677, zero errors

🤖 Generated with Claude Code

Adds a shared buildInCondition() utility (TDD, tests in utils.test.ts)
and uses it in place of exact-equality source_tool filters across
shared-aggregation, sessions, analytics, and facets routes. A single
CSV value still produces an equivalent IN (?) clause, so existing
single-value behavior is unchanged; a comma-separated value now
filters across multiple source tools in one query. Prepares the
server for the dashboard's source-tool multi-select filter.
Replaces the hardcoded single-select SourceToolSelect (11 static
entries) with SourceToolMultiSelect, populated from
useAvailableSourceTools() (a thin wrapper around
fetchFacetAggregation({period:'all'}) -> sourceTools), so the option
list reflects what's actually in the DB and new source tools appear
without a code change.

Converts all 5 call sites (InsightsPage, JournalPage, AnalyticsPage,
SessionListPanel, ProjectNav/SessionsPage) to the existing
comma-joined-string filter-state convention already used for
filters.project, converting to/from string[] only at the component
boundary. Deletes the now-unused SourceToolSelect.tsx and its
hardcoded SOURCE_TOOLS array.

Depends on the server accepting CSV source/sourceTool filter values
(prior commit).
@ClaudiaFang
ClaudiaFang merged commit e27ff89 into master Jul 21, 2026
1 check passed
@ClaudiaFang
ClaudiaFang deleted the feature/source-tool-multiselect branch July 21, 2026 16:03
ClaudiaFang pushed a commit that referenced this pull request Jul 23, 2026
docs: full content for dashboard guides — sessions, insights, analytics, export
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