@@ -15,6 +15,8 @@ import {
1515 Button ,
1616 Center ,
1717 Checkbox ,
18+ Collapse ,
19+ Divider ,
1820 Flex ,
1921 Group ,
2022 Loader ,
@@ -1110,6 +1112,14 @@ const DBSearchPageFiltersComponent = ({
11101112 'hdx-show-filter-counts' ,
11111113 true ,
11121114 ) ;
1115+ const [ isFiltersExpanded , setFiltersExpanded ] = useLocalStorage (
1116+ 'hdx-filters-expanded' ,
1117+ true ,
1118+ ) ;
1119+ const [ isSharedFiltersExpanded , setSharedFiltersExpanded ] = useLocalStorage (
1120+ 'hdx-shared-filters-expanded' ,
1121+ true ,
1122+ ) ;
11131123 const { size, startResize } = useResizable ( 16 , 'left' ) ;
11141124
11151125 const { data : jsonColumns } = useJsonColumns ( {
@@ -1691,18 +1701,30 @@ const DBSearchPageFiltersComponent = ({
16911701 < Text size = "xxs" c = "dimmed" fw = "bold" >
16921702 Analysis Mode
16931703 </ Text >
1694- { onCollapse && (
1695- < Tooltip label = "Hide filters" position = "bottom" >
1696- < ActionIcon
1697- variant = "subtle"
1698- size = "xs"
1699- onClick = { onCollapse }
1700- aria-label = "Hide filters"
1701- >
1702- < IconArrowBarToLeft size = { 14 } />
1703- </ ActionIcon >
1704- </ Tooltip >
1705- ) }
1704+ < Group gap = { 0 } >
1705+ < FilterSettingsPanel
1706+ isSharedFiltersVisible = { isSharedFiltersVisible }
1707+ onSharedFiltersVisibilityChange = { setSharedFiltersVisible }
1708+ showFilterCounts = { showFilterCounts }
1709+ onShowFilterCountsChange = { setShowFilterCounts }
1710+ hasPersonalPins = { hasPersonalPins }
1711+ onResetPersonalPins = { resetPersonalPins }
1712+ hasSharedPins = { hasSharedPins }
1713+ onResetSharedFilters = { resetSharedFilters }
1714+ />
1715+ { onCollapse && (
1716+ < Tooltip label = "Hide filters" position = "bottom" >
1717+ < ActionIcon
1718+ variant = "subtle"
1719+ size = "xs"
1720+ onClick = { onCollapse }
1721+ aria-label = "Hide filters"
1722+ >
1723+ < IconArrowBarToLeft size = { 14 } />
1724+ </ ActionIcon >
1725+ </ Tooltip >
1726+ ) }
1727+ </ Group >
17061728 </ Flex >
17071729 < Tabs
17081730 value = { analysisMode }
@@ -1733,6 +1755,10 @@ const DBSearchPageFiltersComponent = ({
17331755 { isSharedFiltersVisible && (
17341756 < SharedFiltersSection
17351757 hasSharedFacets = { sharedFacets . length > 0 }
1758+ opened = { isSharedFiltersExpanded }
1759+ onToggle = { ( ) =>
1760+ setSharedFiltersExpanded ( ! isSharedFiltersExpanded )
1761+ }
17361762 showClearButton = { showSharedClearButton }
17371763 onClearSelections = { clearSharedSelections }
17381764 >
@@ -1743,151 +1769,180 @@ const DBSearchPageFiltersComponent = ({
17431769 </ SharedFiltersSection >
17441770 ) }
17451771
1746- < Flex align = "center" justify = "space-between" >
1747- < Flex className = { isFacetsFetching ? 'effect-pulse' : '' } >
1748- < Text size = "xxs" c = "dimmed" fw = "bold" >
1749- Filters { isFacetsFetching && '···' }
1750- </ Text >
1751- { showRefreshButton && (
1752- < TextButton
1753- label = {
1754- < IconRefresh
1755- size = { 14 }
1756- className = "ms-1"
1757- onClick = { ( ) => setDateRange ( chartConfig . dateRange ) }
1758- />
1759- }
1760- />
1761- ) }
1762- </ Flex >
1763- < Group gap = { 0 } >
1764- { showFiltersClearButton && (
1765- < Tooltip
1766- label = "Clear Filters"
1767- position = "top"
1768- withArrow
1769- fz = "xxs"
1770- color = "gray"
1771- >
1772- < ActionIcon
1773- variant = "subtle"
1774- color = "gray"
1775- size = "xs"
1776- onClick = { clearRegularSelections }
1777- aria-label = "Clear Filters"
1778- >
1779- < IconFilterOff size = { 14 } />
1780- </ ActionIcon >
1781- </ Tooltip >
1782- ) }
1783- < FilterSettingsPanel
1784- isSharedFiltersVisible = { isSharedFiltersVisible }
1785- onSharedFiltersVisibilityChange = { setSharedFiltersVisible }
1786- showFilterCounts = { showFilterCounts }
1787- onShowFilterCountsChange = { setShowFilterCounts }
1788- hasPersonalPins = { hasPersonalPins }
1789- onResetPersonalPins = { resetPersonalPins }
1790- hasSharedPins = { hasSharedPins }
1791- onResetSharedFilters = { resetSharedFilters }
1792- />
1793- </ Group >
1794- </ Flex >
1772+ { /* Divider between shared and regular filters */ }
1773+ { isSharedFiltersVisible && sharedFacets . length > 0 && (
1774+ < Divider color = "dark.4" />
1775+ ) }
17951776
1796- { analysisMode === 'results' && (
1797- < Checkbox
1798- size = { 13 as any }
1799- checked = { denoiseResults }
1800- ms = "6px"
1801- label = {
1802- < Tooltip
1803- openDelay = { 200 }
1804- color = "gray "
1805- position = "right "
1806- withArrow
1807- label = "Denoise results will visually remove events matching common event patterns from the results table."
1777+ { /* Collapsible "Filters" section */ }
1778+ < Stack gap = "xs" >
1779+ < Flex align = "center" justify = "space-between" >
1780+ < UnstyledButton
1781+ onClick = { ( ) => setFiltersExpanded ( ! isFiltersExpanded ) }
1782+ style = { { flex : 1 } }
1783+ >
1784+ < Text
1785+ size = "xxs "
1786+ c = "dimmed "
1787+ fw = "bold"
1788+ className = { isFacetsFetching ? 'effect-pulse' : '' }
18081789 >
1809- < Text size = "xs" mt = "-2px" component = "div" >
1810- < Group gap = { 2 } >
1811- < IconShadow
1790+ Filters { isFacetsFetching && '···' }
1791+ </ Text >
1792+ </ UnstyledButton >
1793+ < Group gap = { 0 } wrap = "nowrap" >
1794+ { showRefreshButton && (
1795+ < TextButton
1796+ label = {
1797+ < IconRefresh
18121798 size = { 14 }
1813- style = { { display : 'inline' , verticalAlign : 'middle' } }
1799+ className = "ms-1"
1800+ onClick = { ( ) => setDateRange ( chartConfig . dateRange ) }
18141801 />
1815- Denoise Results
1816- </ Group >
1817- </ Text >
1818- </ Tooltip >
1819- }
1820- onChange = { ( ) => setDenoiseResults ( ! denoiseResults ) }
1821- />
1822- ) }
1823-
1824- { source ?. kind === SourceKind . Trace &&
1825- source . parentSpanIdExpression && (
1826- < Checkbox
1827- size = { 13 as any }
1828- checked = { isRootSpansOnly }
1829- ms = "6px"
1830- label = {
1802+ }
1803+ />
1804+ ) }
1805+ { showFiltersClearButton && (
18311806 < Tooltip
1832- openDelay = { 200 }
1833- color = "gray"
1834- position = "right"
1807+ label = "Clear Filters"
1808+ position = "top"
18351809 withArrow
1836- label = "Only show root spans (spans with no parent span)."
1810+ fz = "xxs"
1811+ color = "gray"
18371812 >
1838- < Text size = "xs" mt = "-2px" component = "div" >
1839- < Group gap = { 2 } >
1840- < IconSitemap
1841- size = { 14 }
1842- style = { { display : 'inline' , verticalAlign : 'middle' } }
1843- />
1844- Root Spans Only
1845- </ Group >
1846- </ Text >
1813+ < ActionIcon
1814+ variant = "subtle"
1815+ color = "gray"
1816+ size = "xs"
1817+ onClick = { clearRegularSelections }
1818+ aria-label = "Clear Filters"
1819+ >
1820+ < IconFilterOff size = { 14 } / >
1821+ </ ActionIcon >
18471822 </ Tooltip >
1848- }
1849- onChange = { event => setRootSpansOnly ( event . target . checked ) }
1850- />
1851- ) }
1852-
1853- { isLoading || isFacetsLoading ? (
1854- < Flex align = "center" justify = "center" >
1855- < Loader size = "xs" color = "gray" />
1823+ ) }
1824+ < UnstyledButton
1825+ onClick = { ( ) => setFiltersExpanded ( ! isFiltersExpanded ) }
1826+ >
1827+ < IconChevronDown
1828+ size = { 14 }
1829+ color = "var(--mantine-color-gray-6)"
1830+ style = { {
1831+ transition : 'transform 0.2s ease-in-out' ,
1832+ transform : isFiltersExpanded
1833+ ? 'rotate(0deg)'
1834+ : 'rotate(-90deg)' ,
1835+ } }
1836+ />
1837+ </ UnstyledButton >
1838+ </ Group >
18561839 </ Flex >
1857- ) : (
1858- shownFacets . length === 0 && (
1859- < Text size = "xxs" > No filters available</ Text >
1860- )
1861- ) }
1862- { /* Show facets even when loading to ensure pinned filters are visible while loading */ }
1863- { renderFacetList ( shownFacets ) }
1864-
1865- < Button
1866- variant = "secondary"
1867- size = "compact-xs"
1868- loading = { isFacetsFetching }
1869- rightSection = {
1870- showMoreFields ? (
1871- < IconChevronUp size = { 14 } />
1872- ) : (
1873- < IconChevronDown size = { 14 } />
1874- )
1875- }
1876- onClick = { ( ) => setShowMoreFields ( ! showMoreFields ) }
1877- >
1878- { showMoreFields ? 'Less filters' : 'More filters' }
1879- </ Button >
1880-
1881- { showMoreFields && (
1882- < div >
1883- < Text size = "xs" fw = "bold" >
1884- Not seeing a filter?
1885- </ Text >
1886- < Text size = "xxs" >
1887- { `Try searching instead (e.g. column:foo)` }
1888- </ Text >
1889- </ div >
1890- ) }
1840+ < Collapse in = { isFiltersExpanded } >
1841+ < Stack gap = "sm" >
1842+ { analysisMode === 'results' && (
1843+ < Checkbox
1844+ size = { 13 as any }
1845+ checked = { denoiseResults }
1846+ ms = "6px"
1847+ label = {
1848+ < Tooltip
1849+ openDelay = { 200 }
1850+ color = "gray"
1851+ position = "right"
1852+ withArrow
1853+ label = "Denoise results will visually remove events matching common event patterns from the results table."
1854+ >
1855+ < Text size = "xs" mt = "-2px" component = "div" >
1856+ < Group gap = { 2 } >
1857+ < IconShadow
1858+ size = { 14 }
1859+ style = { {
1860+ display : 'inline' ,
1861+ verticalAlign : 'middle' ,
1862+ } }
1863+ />
1864+ Denoise Results
1865+ </ Group >
1866+ </ Text >
1867+ </ Tooltip >
1868+ }
1869+ onChange = { ( ) => setDenoiseResults ( ! denoiseResults ) }
1870+ />
1871+ ) }
1872+
1873+ { source ?. kind === SourceKind . Trace &&
1874+ source . parentSpanIdExpression && (
1875+ < Checkbox
1876+ size = { 13 as any }
1877+ checked = { isRootSpansOnly }
1878+ ms = "6px"
1879+ label = {
1880+ < Tooltip
1881+ openDelay = { 200 }
1882+ color = "gray"
1883+ position = "right"
1884+ withArrow
1885+ label = "Only show root spans (spans with no parent span)."
1886+ >
1887+ < Text size = "xs" mt = "-2px" component = "div" >
1888+ < Group gap = { 2 } >
1889+ < IconSitemap
1890+ size = { 14 }
1891+ style = { {
1892+ display : 'inline' ,
1893+ verticalAlign : 'middle' ,
1894+ } }
1895+ />
1896+ Root Spans Only
1897+ </ Group >
1898+ </ Text >
1899+ </ Tooltip >
1900+ }
1901+ onChange = { event => setRootSpansOnly ( event . target . checked ) }
1902+ />
1903+ ) }
1904+
1905+ { isLoading || isFacetsLoading ? (
1906+ < Flex align = "center" justify = "center" >
1907+ < Loader size = "xs" color = "gray" />
1908+ </ Flex >
1909+ ) : (
1910+ shownFacets . length === 0 && (
1911+ < Text size = "xxs" > No filters available</ Text >
1912+ )
1913+ ) }
1914+ { /* Show facets even when loading to ensure pinned filters are visible while loading */ }
1915+ { renderFacetList ( shownFacets ) }
1916+
1917+ < Button
1918+ variant = "secondary"
1919+ size = "compact-xs"
1920+ loading = { isFacetsFetching }
1921+ rightSection = {
1922+ showMoreFields ? (
1923+ < IconChevronUp size = { 14 } />
1924+ ) : (
1925+ < IconChevronDown size = { 14 } />
1926+ )
1927+ }
1928+ onClick = { ( ) => setShowMoreFields ( ! showMoreFields ) }
1929+ >
1930+ { showMoreFields ? 'Less filters' : 'More filters' }
1931+ </ Button >
1932+
1933+ { showMoreFields && (
1934+ < div >
1935+ < Text size = "xs" fw = "bold" >
1936+ Not seeing a filter?
1937+ </ Text >
1938+ < Text size = "xxs" >
1939+ { `Try searching instead (e.g. column:foo)` }
1940+ </ Text >
1941+ </ div >
1942+ ) }
1943+ </ Stack >
1944+ </ Collapse >
1945+ </ Stack >
18911946 </ Stack >
18921947 </ ScrollArea >
18931948 </ Box >
0 commit comments