feat: dynamic multi-select source-tool filter - #20
Merged
Conversation
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
pushed a commit
that referenced
this pull request
Jul 23, 2026
docs: full content for dashboard guides — sessions, insights, analytics, export
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
buildInCondition()(TDD,server/src/utils.ts/utils.test.ts) and swapped the foursource_tool = ?exact-equality filters (shared-aggregation.ts,sessions.ts,analytics.ts,facets.ts) forsource_tool IN (...), built from a comma-split of the incoming query param. A single value still produces an equivalentIN (?)clause, so existing single-value behavior is unchanged. Wire format stays a single CSV string (Zod schemas unchanged) — no new endpoints, consistent with howproject/homeId/typefilters already work.useAvailableSourceTools()(dashboard/src/hooks/useFacets.ts), a thin React Query wrapper over the existingfetchFacetAggregation({period:'all'})->sourceTools: string[], 5-minutestaleTime. AddedSourceToolMultiSelect.tsxmodeled directly onProjectMultiSelect.tsx(Popover + Checkbox,value: string[]/onValueChange), self-fetching its option list, usingSOURCE_TOOL_DISPLAY_NAMESfor labels (falls back to title-case) and aDOT_COLORSmap (moved from the old component, falls back to neutral gray for unknown ids).InsightsPage,JournalPage,AnalyticsPage,SessionListPanel,ProjectNav(+SessionsPageas the unchanged parent) — to the repo's existing comma-joined-string filter-state convention (same pattern already used forfilters.project), converting to/fromstring[]only at the component boundary.SourceToolSelect.tsxand its hardcodedSOURCE_TOOLSarray — confirmed via grep no remaining imports.Schema Impact
source/sourceToolnow accept CSV; Zod schemas remainz.string().optional())source/sourceToolfilters on/api/sessions,/api/analytics/cache-by-source,/api/facets,/api/facets/aggregated,/api/facets/missing,/api/facets/missing-pq,/api/facets/outdated-pqnow accept comma-separated valuesTesting
buildInCondition()inserver/src/utils.test.ts(7 cases, written first and verified failing before implementation)sessions.test.ts,analytics.test.ts,shared-aggregation.test.ts) — existing single-value tests kept and updated only where thewhere-clause string shape changed (= ?->IN (?))cd server && pnpm build && pnpm test— 677/677 passingcd dashboard && pnpm build— clean;npx tsc --noEmit— zero errors;pnpm test— 15/15 passingpnpm build && pnpm testfrom repo root — cli 917/917, dashboard 15/15, server 677/677, zero errors🤖 Generated with Claude Code