mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-10-30 14:49:14 +00:00
180 lines
5.2 KiB
TypeScript
180 lines
5.2 KiB
TypeScript
import {Component, Fragment} from 'react';
|
|
import type {Location} from 'history';
|
|
|
|
import Panel from 'sentry/components/panels/panel';
|
|
import type {Organization} from 'sentry/types';
|
|
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<Props> {
|
|
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 (
|
|
<HistogramQuery
|
|
location={location}
|
|
orgSlug={organization.slug}
|
|
eventView={eventView}
|
|
numBuckets={NUM_BUCKETS}
|
|
fields={zoomed ? [vital] : []}
|
|
min={min}
|
|
max={max}
|
|
precision={precision}
|
|
dataFilter={dataFilter}
|
|
>
|
|
{results => {
|
|
const loading = zoomed ? results.isLoading : isLoading;
|
|
const errored = zoomed ? results.error !== null : error;
|
|
const chartData = zoomed ? results.histograms?.[vital] ?? histogram : histogram;
|
|
return (
|
|
<VitalCard
|
|
location={location}
|
|
isLoading={loading}
|
|
error={errored}
|
|
vital={vital}
|
|
vitalDetails={vitalDetails}
|
|
summaryData={data}
|
|
chartData={chartData}
|
|
colors={color}
|
|
eventView={eventView}
|
|
organization={organization}
|
|
min={min}
|
|
max={max}
|
|
precision={precision}
|
|
dataFilter={dataFilter}
|
|
/>
|
|
);
|
|
}}
|
|
</HistogramQuery>
|
|
);
|
|
}
|
|
|
|
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<WebVital, {end: string | undefined; start: string | undefined}>
|
|
>,
|
|
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 (
|
|
<HistogramQuery
|
|
location={location}
|
|
orgSlug={organization.slug}
|
|
eventView={eventView}
|
|
numBuckets={NUM_BUCKETS}
|
|
fields={vitals}
|
|
min={min}
|
|
max={max}
|
|
precision={precision}
|
|
dataFilter={dataFilter}
|
|
>
|
|
{multiHistogramResults => {
|
|
const isLoading = summaryResults.isLoading || multiHistogramResults.isLoading;
|
|
const error =
|
|
summaryResults.error !== null || multiHistogramResults.error !== null;
|
|
return (
|
|
<Fragment>
|
|
{vitals.map((vital, index) => {
|
|
const data = summaryResults?.vitalsData?.[vital] ?? null;
|
|
const histogram = multiHistogramResults.histograms?.[vital] ?? [];
|
|
const {start, end} = bounds[vital] ?? {};
|
|
|
|
return (
|
|
<Fragment key={vital}>
|
|
{this.renderVitalCard(
|
|
vital,
|
|
isLoading,
|
|
error,
|
|
data,
|
|
histogram,
|
|
[colors[index]],
|
|
parseBound(start, precision),
|
|
parseBound(end, precision),
|
|
precision
|
|
)}
|
|
</Fragment>
|
|
);
|
|
})}
|
|
</Fragment>
|
|
);
|
|
}}
|
|
</HistogramQuery>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
const {results} = this.props;
|
|
|
|
return (
|
|
<Panel>
|
|
<Fragment>
|
|
{VITAL_GROUPS.map(vitalGroup => (
|
|
<Fragment key={vitalGroup.vitals.join('')}>
|
|
{this.renderVitalGroup(vitalGroup, results)}
|
|
</Fragment>
|
|
))}
|
|
</Fragment>
|
|
</Panel>
|
|
);
|
|
}
|
|
}
|
|
|
|
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;
|