import {Component, Fragment} from 'react'; import type {Location} from 'history'; import Panel from 'sentry/components/panels/panel'; import type {Organization} from 'sentry/types/organization'; import type EventView from 'sentry/utils/discover/eventView'; import type {WebVital} from 'sentry/utils/fields'; import HistogramQuery from 'sentry/utils/performance/histogram/histogramQuery'; import type {DataFilter, HistogramData} from 'sentry/utils/performance/histogram/types'; import {WEB_VITAL_DETAILS} from 'sentry/utils/performance/vitals/constants'; import type {VitalGroup} from 'sentry/utils/performance/vitals/types'; import type {VitalData} from 'sentry/utils/performance/vitals/vitalsCardsDiscoverQuery'; import {decodeScalar} from 'sentry/utils/queryString'; import {NUM_BUCKETS, VITAL_GROUPS} from './constants'; import VitalCard from './vitalCard'; type Props = { eventView: EventView; location: Location; organization: Organization; results: object; dataFilter?: DataFilter; }; class VitalsPanel extends Component { renderVitalCard( vital: WebVital, isLoading: boolean, error: boolean, data: VitalData | null, histogram: HistogramData, color: [string], min?: number, max?: number, precision?: number ) { const {location, organization, eventView, dataFilter} = this.props; const vitalDetails = WEB_VITAL_DETAILS[vital]; const zoomed = min !== undefined || max !== undefined; return ( {results => { const loading = zoomed ? results.isLoading : isLoading; const errored = zoomed ? results.error !== null : error; const chartData = zoomed ? results.histograms?.[vital] ?? histogram : histogram; return ( ); }} ); } renderVitalGroup(group: VitalGroup, summaryResults) { const {location, organization, eventView, dataFilter} = this.props; const {vitals, colors, min, max, precision} = group; const bounds = vitals.reduce( ( allBounds: Partial< Record >, vital: WebVital ) => { const slug = WEB_VITAL_DETAILS[vital].slug; allBounds[vital] = { start: decodeScalar(location.query[`${slug}Start`]), end: decodeScalar(location.query[`${slug}End`]), }; return allBounds; }, {} ); return ( {multiHistogramResults => { const isLoading = summaryResults.isLoading || multiHistogramResults.isLoading; const error = summaryResults.error !== null || multiHistogramResults.error !== null; return ( {vitals.map((vital, index) => { const data = summaryResults?.vitalsData?.[vital] ?? null; const histogram = multiHistogramResults.histograms?.[vital] ?? []; const {start, end} = bounds[vital] ?? {}; return ( {this.renderVitalCard( vital, isLoading, error, data, histogram, [colors[index]], parseBound(start, precision), parseBound(end, precision), precision )} ); })} ); }} ); } render() { const {results} = this.props; return ( {VITAL_GROUPS.map(vitalGroup => ( {this.renderVitalGroup(vitalGroup, results)} ))} ); } } function parseBound( boundString: string | undefined, precision: number | undefined ): number | undefined { if (boundString === undefined) { return undefined; } if (precision === undefined || precision === 0) { return parseInt(boundString, 10); } return parseFloat(boundString); } export default VitalsPanel;