123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- import {useEffect, useState} from 'react';
- import {ApiResult} from 'sentry/api';
- import {DateString, MetricsApiRequestQuery, MetricsApiResponse} from 'sentry/types';
- import {
- getMetricsApiRequestQuery,
- mapToMRIFields,
- MetricsQuery,
- } from 'sentry/utils/metrics';
- import {useApiQuery} from 'sentry/utils/queryClient';
- import useOrganization from 'sentry/utils/useOrganization';
- function getRefetchInterval(
- data: ApiResult | undefined,
- interval: string
- ): number | false {
- // no data means request failed - don't refetch
- if (!data) {
- return false;
- }
- if (interval === '10s') {
- // refetch every 10 seconds
- return 10 * 1000;
- }
- // refetch every 60 seconds
- return 60 * 1000;
- }
- export function useMetricsData(
- {mri, op, datetime, projects, environments, query, groupBy}: MetricsQuery,
- overrides: Partial<MetricsApiRequestQuery> = {}
- ) {
- const organization = useOrganization();
- const useNewMetricsLayer = organization.features.includes(
- 'metrics-api-new-metrics-layer'
- );
- const field = op ? `${op}(${mri})` : mri;
- const queryToSend = getMetricsApiRequestQuery(
- {
- field,
- query: `${query}`,
- groupBy,
- },
- {datetime, projects, environments},
- {...overrides, useNewMetricsLayer}
- );
- const metricsApiRepsonse = useApiQuery<MetricsApiResponse>(
- [`/organizations/${organization.slug}/metrics/data/`, {query: queryToSend}],
- {
- retry: 0,
- staleTime: 0,
- refetchOnReconnect: true,
- refetchOnWindowFocus: true,
- refetchInterval: data => getRefetchInterval(data, queryToSend.interval),
- }
- );
- mapToMRIFields(metricsApiRepsonse.data, [field]);
- return metricsApiRepsonse;
- }
- // Wraps useMetricsData and provides two additional features:
- // 1. return data is undefined only during the initial load
- // 2. provides a callback to trim the data to a specific time range when chart zoom is used
- export function useMetricsDataZoom(props: MetricsQuery) {
- const [metricsData, setMetricsData] = useState<MetricsApiResponse | undefined>();
- const {data: rawData, isLoading, isError, error} = useMetricsData(props);
- useEffect(() => {
- if (rawData) {
- setMetricsData(rawData);
- }
- }, [rawData]);
- const trimData = (start, end): MetricsApiResponse | undefined => {
- if (!metricsData) {
- return metricsData;
- }
- // find the index of the first interval that is greater than the start time
- const startIndex = metricsData.intervals.findIndex(interval => interval >= start) - 1;
- const endIndex = metricsData.intervals.findIndex(interval => interval >= end);
- if (startIndex === -1 || endIndex === -1) {
- return metricsData;
- }
- return {
- ...metricsData,
- intervals: metricsData.intervals.slice(startIndex, endIndex),
- groups: metricsData.groups.map(group => ({
- ...group,
- series: Object.fromEntries(
- Object.entries(group.series).map(([seriesName, series]) => [
- seriesName,
- series.slice(startIndex, endIndex),
- ])
- ),
- })),
- };
- };
- return {
- data: metricsData,
- isLoading,
- isError,
- error,
- onZoom: (start: DateString, end: DateString) => {
- setMetricsData(trimData(start, end));
- },
- };
- }
|