123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import {useTheme} from '@emotion/react';
- import styled from '@emotion/styled';
- import ChartZoom from 'sentry/components/charts/chartZoom';
- import MarkArea from 'sentry/components/charts/components/markArea';
- import MarkLine from 'sentry/components/charts/components/markLine';
- import type {LineChartSeries} from 'sentry/components/charts/lineChart';
- import {LineChart} from 'sentry/components/charts/lineChart';
- import getDuration from 'sentry/utils/duration/getDuration';
- import usePageFilters from 'sentry/utils/usePageFilters';
- import useRouter from 'sentry/utils/useRouter';
- import {
- PERFORMANCE_SCORE_MEDIANS,
- PERFORMANCE_SCORE_P90S,
- } from 'sentry/views/insights/browser/webVitals/utils/scoreThresholds';
- interface Props {
- webVitalSeries: LineChartSeries;
- }
- export function WebVitalStatusLineChart({webVitalSeries}: Props) {
- const theme = useTheme();
- const router = useRouter();
- const pageFilters = usePageFilters();
- const {period, start, end, utc} = pageFilters.selection.datetime;
- const webVital = webVitalSeries.seriesName;
- const allSeries = [webVitalSeries];
- const seriesIsPoor = webVitalSeries.data?.some(
- ({value}) => value > PERFORMANCE_SCORE_MEDIANS[webVital ?? '']
- );
- const seriesIsMeh = webVitalSeries.data?.some(
- ({value}) => value >= PERFORMANCE_SCORE_P90S[webVital ?? '']
- );
- const seriesIsGood = webVitalSeries.data?.every(
- ({value}) => value < PERFORMANCE_SCORE_P90S[webVital ?? '']
- );
- const goodMarkArea = MarkArea({
- silent: true,
- itemStyle: {
- color: theme.green300,
- opacity: 0.1,
- },
- data: [
- [
- {
- yAxis: PERFORMANCE_SCORE_P90S[webVital ?? ''],
- },
- {
- yAxis: 0,
- },
- ],
- ],
- });
- const mehMarkArea = MarkArea({
- silent: true,
- itemStyle: {
- color: theme.yellow300,
- opacity: 0.1,
- },
- data: [
- [
- {
- yAxis: PERFORMANCE_SCORE_MEDIANS[webVital ?? ''],
- },
- {
- yAxis: PERFORMANCE_SCORE_P90S[webVital ?? ''],
- },
- ],
- ],
- });
- const poorMarkArea = MarkArea({
- silent: true,
- itemStyle: {
- color: theme.red300,
- opacity: 0.1,
- },
- data: [
- [
- {
- yAxis: PERFORMANCE_SCORE_MEDIANS[webVital ?? ''],
- },
- {
- yAxis: Infinity,
- },
- ],
- ],
- });
- const goodMarkLine = MarkLine({
- silent: true,
- lineStyle: {
- color: theme.green300,
- },
- label: {
- formatter: () => 'Good',
- position: 'insideEndBottom',
- color: theme.green300,
- },
- data: [
- {
- yAxis: PERFORMANCE_SCORE_P90S[webVital ?? ''],
- },
- ],
- });
- const mehMarkLine = MarkLine({
- silent: true,
- lineStyle: {
- color: theme.yellow300,
- },
- label: {
- formatter: () => 'Meh',
- position: 'insideEndBottom',
- color: theme.yellow300,
- },
- data: [
- {
- yAxis: PERFORMANCE_SCORE_MEDIANS[webVital ?? ''],
- },
- ],
- });
- const poorMarkLine = MarkLine({
- silent: true,
- lineStyle: {
- color: theme.red300,
- },
- label: {
- formatter: () => 'Poor',
- position: 'insideEndBottom',
- color: theme.red300,
- },
- data: [
- [
- {xAxis: 'min', y: 10},
- {xAxis: 'max', y: 10},
- ],
- ],
- });
- allSeries.push({
- seriesName: '',
- type: 'line',
- markArea: goodMarkArea,
- data: [],
- });
- allSeries.push({
- seriesName: '',
- type: 'line',
- markArea: mehMarkArea,
- data: [],
- });
- allSeries.push({
- seriesName: '',
- type: 'line',
- markArea: poorMarkArea,
- data: [],
- });
- allSeries.push({
- seriesName: '',
- type: 'line',
- markLine: goodMarkLine,
- data: [],
- });
- allSeries.push({
- seriesName: '',
- type: 'line',
- markLine: mehMarkLine,
- data: [],
- });
- if (seriesIsPoor) {
- allSeries.push({
- seriesName: '',
- type: 'line',
- markLine: poorMarkLine,
- data: [],
- });
- }
- const getFormattedDuration = (value: number) => {
- if (value < 1000) {
- return getDuration(value / 1000, 0, true);
- }
- return getDuration(value / 1000, 2, true);
- };
- const getMaxYAxis = () => {
- if (seriesIsPoor) {
- return undefined;
- }
- if (seriesIsMeh) {
- return PERFORMANCE_SCORE_MEDIANS[webVital ?? ''];
- }
- if (seriesIsGood) {
- return PERFORMANCE_SCORE_P90S[webVital ?? ''];
- }
- return undefined;
- };
- const yAxisMax = getMaxYAxis();
- return (
- <ChartContainer>
- {webVital && (
- <ChartZoom router={router} period={period} start={start} end={end} utc={utc}>
- {zoomRenderProps => (
- <LineChart
- {...zoomRenderProps}
- height={240}
- series={allSeries}
- xAxis={{show: false}}
- grid={{
- left: 0,
- right: 15,
- top: 10,
- bottom: 0,
- }}
- yAxis={{
- ...(webVital === 'cls'
- ? {}
- : {axisLabel: {formatter: getFormattedDuration}}),
- max: yAxisMax,
- }}
- tooltip={webVital === 'cls' ? {} : {valueFormatter: getFormattedDuration}}
- />
- )}
- </ChartZoom>
- )}
- </ChartContainer>
- );
- }
- const ChartContainer = styled('div')`
- position: relative;
- flex: 1;
- `;
|