Files
triggerdotdev--trigger.dev/apps/webapp/app/hooks/useElementVisibility.ts
Matt Aitken bc0d1ff59a Metrics dashboards (#3019)
Summary
- Implemented metrics dashboards with a built-in dashboard and custom
dashboards
- Added a "Big number” display type

What changed
- New data format for metric layouts and saving/editing layouts
(editing, saving, cancel revert)
  - QueryWidget usable on Query page and Metrics dashboards
  - Time filtering, auto-reloading and timeBucket() auto-bin support
- Filters added to metrics; widget popover/improved history and blank
states
- Side menu:
- Metrics/Insights section with icons, colors, padding, collapsible
behavior and reordering of custom dashboards
- Move action logic into service for reuse and API querying; refactor
reordering for reuse
<!-- devin-review-badge-begin -->

---

<a
href="https://app.devin.ai/review/triggerdotdev/trigger.dev/pull/3019"
target="_blank">
  <picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open with Devin">
  </picture>
</a>
<!-- devin-review-badge-end -->

---------

Co-authored-by: James Ritchie <james@trigger.dev>
2026-02-12 17:48:02 +00:00

36 lines
904 B
TypeScript

import { useEffect, useRef } from "react";
type UseElementVisibilityOptions = {
onVisibilityChange?: (isVisible: boolean) => void;
};
export function useElementVisibility({
onVisibilityChange,
}: UseElementVisibilityOptions = {}) {
const ref = useRef<HTMLDivElement>(null);
const isVisibleRef = useRef(false);
const callbackRef = useRef(onVisibilityChange);
callbackRef.current = onVisibilityChange;
useEffect(() => {
const el = ref.current;
if (!el) return;
const observer = new IntersectionObserver(
([entry]) => {
const nowVisible = entry.isIntersecting;
if (isVisibleRef.current !== nowVisible) {
isVisibleRef.current = nowVisible;
callbackRef.current?.(nowVisible);
}
},
{ threshold: 0 }
);
observer.observe(el);
return () => observer.disconnect();
}, []);
return { ref, isVisibleRef };
}