diff --git a/.changeset/collapsible-filter-sidebar.md b/.changeset/collapsible-filter-sidebar.md new file mode 100644 index 00000000..de1aec7e --- /dev/null +++ b/.changeset/collapsible-filter-sidebar.md @@ -0,0 +1,5 @@ +--- +"@hyperdx/app": patch +--- + +feat: Add collapsible filter sidebar toggle to search page diff --git a/agent_docs/code_style.md b/agent_docs/code_style.md index 6d42f333..70ef10ed 100644 --- a/agent_docs/code_style.md +++ b/agent_docs/code_style.md @@ -37,13 +37,25 @@ The project uses Mantine UI with **custom variants** defined in `packages/app/sr | `variant="secondary"` | Secondary actions (Cancel, Clear, auxiliary actions) | `` | | `variant="danger"` | Destructive actions (Delete, Remove, Rotate API Key) | `` | | `variant="link"` | Link-style actions with no background or border (View Details, navigation-style CTAs) | `` | +| `variant="subtle"` | **ActionIcon only.** Transparent background with hover highlight; for toolbar/utility icons that shouldn't draw attention until hovered (collapse toggles, close buttons, auxiliary controls) | `...` | + +### Correct Usage + +```tsx + + + + +... +... +... +... +... +``` ### DO NOT USE (Forbidden Patterns) -The following patterns are **NOT ALLOWED** for Button and ActionIcon: - ```tsx -// ❌ WRONG - Don't use these @@ -54,20 +66,12 @@ The following patterns are **NOT ALLOWED** for Button and ActionIcon: ... ... - -// ✅ CORRECT - Use custom variants - - - - -... -... -... -... ``` **Link variant details**: Renders with no background, no border, and muted text color. On hover, text brightens to full contrast. Use for link-style CTAs that should blend into surrounding content (e.g., "View Details", "View Full Trace"). +**Subtle variant details (ActionIcon only)**: Transparent background with standard text color. On hover, a subtle background highlight appears (`--color-bg-hover`). This is the **default** ActionIcon variant. Use for toolbar icons, collapse toggles, close buttons, and utility controls that should stay unobtrusive but reveal interactivity on hover. Unlike `link`, `subtle` shows a hover background rather than changing text color. + **Note**: `variant="filled"` is still valid for **form inputs** (Select, TextInput, etc.), just not for Button/ActionIcon. ### Icon-Only Buttons → ActionIcon diff --git a/packages/app/src/DBSearchPage.tsx b/packages/app/src/DBSearchPage.tsx index 0cbd8026..1d2a1439 100644 --- a/packages/app/src/DBSearchPage.tsx +++ b/packages/app/src/DBSearchPage.tsx @@ -64,6 +64,7 @@ import { import { notifications } from '@mantine/notifications'; import { IconBolt, + IconLayoutSidebarLeftExpand, IconPlayerPlay, IconPlus, IconTags, @@ -171,6 +172,8 @@ const SearchConfigSchema = z.object({ type SearchConfigFromSchema = z.infer; +const QUERY_KEY_PREFIX = 'search'; + // Helper function to get the default source id export function getDefaultSourceId( sources: { id: string }[] | undefined, @@ -261,6 +264,46 @@ function SearchSubmitButton({ ); } +function ExpandFiltersButton({ onExpand }: { onExpand: () => void }) { + return ( + + + + + + ); +} + +function SearchResultsCountGroup({ + isFilterSidebarCollapsed, + onExpandFilters, + histogramTimeChartConfig, + enableParallelQueries, +}: { + isFilterSidebarCollapsed: boolean; + onExpandFilters: () => void; + histogramTimeChartConfig: BuilderChartConfigWithDateRange; + enableParallelQueries?: boolean; +}) { + return ( + + {isFilterSidebarCollapsed && ( + + )} + + + ); +} + function SearchNumRows({ config, enabled, @@ -278,7 +321,7 @@ function SearchNumRows({ const numRows = data?.[0]?.rows; return ( - + {isLoading ? 'Scanned Rows ...' : error || !numRows @@ -812,6 +855,9 @@ function DBSearchPage() { } }, [analysisMode, setIsLive]); + const [isFilterSidebarCollapsed, setIsFilterSidebarCollapsed] = + useLocalStorage('isFilterSidebarCollapsed', false); + const [denoiseResults, _setDenoiseResults] = useQueryState( 'denoise', parseAsBoolean.withDefault(false), @@ -1174,8 +1220,6 @@ function DBSearchPage() { const [newSourceModalOpened, setNewSourceModalOpened] = useState(false); - const QUERY_KEY_PREFIX = 'search'; - const isAnyQueryFetching = useIsFetching({ queryKey: [QUERY_KEY_PREFIX], @@ -1761,33 +1805,43 @@ function DBSearchPage() { height: '100%', }} > - - - + {!isFilterSidebarCollapsed && ( + + setIsFilterSidebarCollapsed(true)} + {...searchFilters} + /> + + )} {analysisMode === 'pattern' && histogramTimeChartConfig != null && ( - - + + setIsFilterSidebarCollapsed(false) + } + histogramTimeChartConfig={histogramTimeChartConfig} /> - + setIsFilterSidebarCollapsed(false) + } + histogramTimeChartConfig={histogramTimeChartConfig} enableParallelQueries /> diff --git a/packages/app/src/components/DBSearchPageFilters.tsx b/packages/app/src/components/DBSearchPageFilters.tsx index 6f65f917..025a0bdc 100644 --- a/packages/app/src/components/DBSearchPageFilters.tsx +++ b/packages/app/src/components/DBSearchPageFilters.tsx @@ -36,6 +36,7 @@ import { IconChevronRight, IconChevronUp, IconFilterOff, + IconLayoutSidebarLeftCollapse, IconMinus, IconPin, IconPinFilled, @@ -875,6 +876,7 @@ const DBSearchPageFiltersComponent = ({ setFilterRange, onColumnToggle, displayedColumns, + onCollapse, }: { analysisMode: 'results' | 'delta' | 'pattern'; setAnalysisMode: (mode: 'results' | 'delta' | 'pattern') => void; @@ -887,6 +889,7 @@ const DBSearchPageFiltersComponent = ({ setFilterRange: (key: string, range: { min: number; max: number }) => void; onColumnToggle?: (column: string) => void; displayedColumns?: string[]; + onCollapse?: () => void; } & FilterStateHook) => { const setFilterValue = useCallback( ( @@ -1203,9 +1206,23 @@ const DBSearchPageFiltersComponent = ({ }} > - - Analysis Mode - + + + Analysis Mode + + {onCollapse && ( + + + + + + )} + diff --git a/packages/app/src/components/SearchTotalCountChart.tsx b/packages/app/src/components/SearchTotalCountChart.tsx index ce2fde71..e9653cda 100644 --- a/packages/app/src/components/SearchTotalCountChart.tsx +++ b/packages/app/src/components/SearchTotalCountChart.tsx @@ -103,7 +103,7 @@ export default function SearchTotalCountChart({ ); return ( - + {isLoading ? ( ··· Results ) : totalCount !== null && !isError ? (