123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import {useHover} from '@react-aria/interactions';
- import {captureException} from '@sentry/react';
- import type {DiscoverDatasets} from 'sentry/utils/discover/types';
- import {
- type ApiQueryKey,
- fetchDataQuery,
- useApiQuery,
- useQueryClient,
- } from 'sentry/utils/queryClient';
- import useOrganization from 'sentry/utils/useOrganization';
- import usePageFilters from 'sentry/utils/usePageFilters';
- import useProjectFromId from 'sentry/utils/useProjectFromId';
- import {
- getRetryDelay,
- shouldRetryHandler,
- } from 'sentry/views/insights/common/utils/retryHandlers';
- const DEFAULT_HOVER_TIMEOUT = 200;
- /**
- * ProjectTraceItemDetailsEndpoint currently only supports ourlogs dataset
- * TODO: Add SPANS_EAP once the backend supports it.
- */
- type EAPDataset = DiscoverDatasets.OURLOGS;
- export interface UseTraceItemDetailsProps {
- /**
- * Trace items are only supported by EAP.
- */
- dataset: EAPDataset;
- /**
- * Every trace item belongs to a project.
- */
- projectId: string;
- /**
- * Sets referrer parameter in the API Payload. Set of allowed referrers are defined
- * as ALLOWED_EVENTS_REFERRERS on the backend.
- */
- referrer: string;
- /**
- * The trace item ID representing an EAP trace item.
- */
- traceItemId: string;
- /**
- * Alias for `enabled` in react-query.
- */
- enabled?: boolean;
- }
- export type TraceItemAttributes = Record<string, TraceItemResponseAttribute>;
- interface TraceItemDetailsResponse {
- attributes: TraceItemAttributes;
- itemId: string;
- timestamp: string;
- }
- type TraceItemDetailsUrlParams = {
- organizationSlug: string;
- projectSlug: string;
- traceItemId: string;
- };
- type TraceItemDetailsQueryParams = {
- dataset: EAPDataset;
- referrer: string;
- };
- export type TraceItemResponseAttribute =
- | {type: 'str'; value: string}
- | {type: 'int'; value: number}
- | {type: 'float'; value: number}
- | {type: 'bool'; value: boolean};
- /**
- * Query hook fetching trace item details in EAP.
- */
- export function useTraceItemDetails(props: UseTraceItemDetailsProps) {
- const organization = useOrganization();
- const project = useProjectFromId({project_id: props.projectId});
- const {isReady: pageFiltersReady} = usePageFilters();
- const enabled = pageFiltersReady && (props.enabled ?? true) && !!project;
- if (!project) {
- captureException(
- new Error(`Project "${props.projectId}" not found in useTraceItemDetails`)
- );
- }
- const queryParams: TraceItemDetailsQueryParams = {
- referrer: props.referrer,
- dataset: props.dataset,
- };
- const result = useApiQuery<TraceItemDetailsResponse>(
- traceItemDetailsQueryKey({
- urlParams: {
- organizationSlug: organization.slug,
- projectSlug: project?.slug ?? '',
- traceItemId: props.traceItemId,
- },
- queryParams,
- }),
- {
- enabled: enabled && pageFiltersReady,
- retry: shouldRetryHandler,
- retryDelay: getRetryDelay,
- staleTime: Infinity,
- }
- );
- return result;
- }
- function traceItemDetailsQueryKey({
- urlParams,
- queryParams,
- }: {
- queryParams: TraceItemDetailsQueryParams;
- urlParams: TraceItemDetailsUrlParams;
- }): ApiQueryKey {
- const query: Record<string, string | string[]> = {
- dataset: queryParams.dataset,
- referrer: queryParams.referrer,
- };
- return [
- `/projects/${urlParams.organizationSlug}/${urlParams.projectSlug}/trace-items/${urlParams.traceItemId}/`,
- {query},
- ];
- }
- export function usePrefetchTraceItemDetailsOnHover({
- traceItemId,
- projectId,
- dataset,
- referrer,
- hoverPrefetchDisabled,
- sharedHoverTimeoutRef,
- }: UseTraceItemDetailsProps & {
- /**
- * A ref to a shared timeout so multiple hover events can be handled
- * without creating multiple timeouts and firing multiple prefetches.
- */
- sharedHoverTimeoutRef: React.MutableRefObject<NodeJS.Timeout | null>;
- /**
- * Whether the hover prefetch should be disabled.
- */
- hoverPrefetchDisabled?: boolean;
- }) {
- const organization = useOrganization();
- const project = useProjectFromId({project_id: projectId});
- const queryClient = useQueryClient();
- const {hoverProps} = useHover({
- onHoverStart: () => {
- if (sharedHoverTimeoutRef.current) {
- clearTimeout(sharedHoverTimeoutRef.current);
- }
- sharedHoverTimeoutRef.current = setTimeout(() => {
- queryClient.prefetchQuery({
- queryKey: traceItemDetailsQueryKey({
- urlParams: {
- organizationSlug: organization.slug,
- projectSlug: project?.slug ?? '',
- traceItemId,
- },
- queryParams: {
- dataset,
- referrer,
- },
- }),
- queryFn: fetchDataQuery,
- staleTime: 30_000,
- });
- }, DEFAULT_HOVER_TIMEOUT);
- },
- onHoverEnd: () => {
- if (sharedHoverTimeoutRef.current) {
- clearTimeout(sharedHoverTimeoutRef.current);
- }
- },
- isDisabled: hoverPrefetchDisabled,
- });
- return hoverProps;
- }
|