Compare commits

...

1 Commits

Author SHA1 Message Date
aks07
4902a5c147 fix(quick-filters): size the settings drawer from its anchor to the viewport bottom
The drawer was sized with per-page viewport math that did not account for the
trial/payment banners, so its save/discard footer rendered below the fold and
users could not save their filter edits. Measure from the rendered top edge to
the viewport bottom instead.
2026-09-19 19:15:45 +05:30
3 changed files with 50 additions and 17 deletions

View File

@@ -1,4 +1,4 @@
import { useMemo, useState } from 'react';
import { useMemo, useRef, useState } from 'react';
import {
ArrowUpToLine,
Filter,
@@ -40,6 +40,7 @@ import CheckboxV2 from './FilterRenderers/Checkbox/v2/CheckboxFilterV2';
import Duration from './FilterRenderers/Duration/Duration';
import Slider from './FilterRenderers/Slider/Slider';
import useFilterConfig from './hooks/useFilterConfig';
import { useViewportAnchoredHeight } from './hooks/useViewportAnchoredHeight';
import QuickFiltersSettings from './QuickFiltersSettings/QuickFiltersSettings';
import { FiltersType, IQuickFiltersProps, QuickFiltersSource } from './types';
@@ -59,6 +60,11 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element {
useFieldApis,
} = props;
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const settingsDrawerRef = useRef<HTMLDivElement>(null);
const settingsDrawerHeight = useViewportAnchoredHeight(
settingsDrawerRef,
isSettingsOpen,
);
const [params, setParams] = useApiMonitoringParams();
const showIP = params.showIP ?? true;
@@ -399,6 +405,7 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element {
</div>
<div className="quick-filters-settings-container">
<div
ref={settingsDrawerRef}
className={classNames(
'quick-filters-settings',
{
@@ -406,6 +413,7 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element {
},
className,
)}
style={settingsDrawerHeight ? { height: settingsDrawerHeight } : undefined}
>
{isSettingsOpen && (
<QuickFiltersSettings

View File

@@ -6,27 +6,15 @@
left: 0;
z-index: 999;
width: 342px;
// Full height of the settings container, which stretches to the sidebar's
// laid-out height. Viewport-based heights broke whenever a banner (trial,
// payment) pushed the page down.
height: 100%;
background: var(--l1-background);
transition: width 0.05s ease-in-out;
overflow: hidden;
color: var(--l1-foreground);
&.qf-logs-explorer {
height: calc(100vh - 45px);
}
&.qf-exceptions {
height: 100vh;
}
&.qf-api-monitoring {
height: calc(100vh - 45px);
}
&.qf-traces-explorer {
height: calc(100vh - 45px);
}
&.hidden {
width: 0;
}

View File

@@ -0,0 +1,37 @@
import { RefObject, useLayoutEffect, useState } from 'react';
/**
* Height from the element's rendered top edge down to the viewport bottom.
* The settings drawer is absolutely positioned inside a section that can
* extend below the fold, and its top offset moves with whatever is rendered
* above (top nav, trial/payment banners), so a static css height cannot know
* where the viewport ends.
*/
export function useViewportAnchoredHeight(
ref: RefObject<HTMLElement>,
enabled: boolean,
): number | undefined {
const [height, setHeight] = useState<number>();
useLayoutEffect((): (() => void) | undefined => {
if (!enabled || !ref.current) {
return undefined;
}
const el = ref.current;
const update = (): void => {
const { top } = el.getBoundingClientRect();
setHeight(Math.max(0, window.innerHeight - top));
};
update();
window.addEventListener('resize', update);
window.addEventListener('scroll', update, true);
return (): void => {
window.removeEventListener('resize', update);
window.removeEventListener('scroll', update, true);
};
}, [ref, enabled]);
return enabled ? height : undefined;
}