11import { useMemo } from 'react' ;
22import { type Theme } from '@emotion/react' ;
3- import styled from '@emotion/styled' ;
43import type { YAXisComponentOption } from 'echarts' ;
54
5+ import Feature from 'sentry/components/acl/feature' ;
66import { AreaChart , type AreaChartProps } from 'sentry/components/charts/areaChart' ;
77import { defaultFormatAxisLabel } from 'sentry/components/charts/components/tooltip' ;
88import ErrorPanel from 'sentry/components/charts/errorPanel' ;
99import { useChartZoom } from 'sentry/components/charts/useChartZoom' ;
1010import { Alert } from 'sentry/components/core/alert' ;
11- import { Flex } from 'sentry/components/core/layout' ;
11+ import { LinkButton } from 'sentry/components/core/button/linkButton' ;
12+ import { Container , Flex } from 'sentry/components/core/layout' ;
1213import { normalizeDateTimeParams } from 'sentry/components/organizations/pageFilters/parse' ;
1314import Placeholder from 'sentry/components/placeholder' ;
1415import { IconWarning } from 'sentry/icons' ;
1516import { t } from 'sentry/locale' ;
1617import { space } from 'sentry/styles/space' ;
1718import type { GroupOpenPeriod } from 'sentry/types/group' ;
1819import type { MetricDetector , SnubaQuery } from 'sentry/types/workflowEngine/detectors' ;
20+ import { decodeScalar } from 'sentry/utils/queryString' ;
1921import type RequestError from 'sentry/utils/requestError/requestError' ;
2022import { useLocation } from 'sentry/utils/useLocation' ;
2123import { useNavigate } from 'sentry/utils/useNavigate' ;
24+ import useOrganization from 'sentry/utils/useOrganization' ;
2225import {
2326 buildDetectorZoomQuery ,
2427 computeZoomRangeMs ,
2528} from 'sentry/views/detectors/components/details/common/buildDetectorZoomQuery' ;
29+ import { getDetectorOpenInDestination } from 'sentry/views/detectors/components/details/metric/getDetectorOpenInDestination' ;
2630import { useDetectorChartAxisBounds } from 'sentry/views/detectors/components/details/metric/utils/useDetectorChartAxisBounds' ;
2731import { getDatasetConfig } from 'sentry/views/detectors/datasetConfig/getDatasetConfig' ;
2832import { getDetectorDataset } from 'sentry/views/detectors/datasetConfig/getDetectorDataset' ;
@@ -370,10 +374,73 @@ export function useMetricDetectorChart({
370374 } ;
371375}
372376
377+ interface OpenInButtonProps {
378+ detector : MetricDetector ;
379+ }
380+
381+ function OpenInButton ( { detector} : OpenInButtonProps ) {
382+ const organization = useOrganization ( ) ;
383+ const location = useLocation ( ) ;
384+ const destination = getDetectorOpenInDestination ( {
385+ detector,
386+ organization,
387+ statsPeriod : decodeScalar ( location . query . statsPeriod ) ,
388+ start : decodeScalar ( location . query . start ) ,
389+ end : decodeScalar ( location . query . end ) ,
390+ } ) ;
391+
392+ if ( ! destination ?. to ) {
393+ return null ;
394+ }
395+
396+ return (
397+ < Feature features = "visibility-explore-view" >
398+ < LinkButton size = "xs" to = { destination . to } >
399+ { destination . buttonText }
400+ </ LinkButton >
401+ </ Feature >
402+ ) ;
403+ }
404+
405+ function ChartContainer ( {
406+ children,
407+ overflow,
408+ } : {
409+ children : React . ReactNode ;
410+ overflow ?: 'hidden' ;
411+ } ) {
412+ return (
413+ < Container border = "muted" radius = "md" overflow = { overflow } >
414+ { children }
415+ </ Container >
416+ ) ;
417+ }
418+
419+ function ChartBody ( { children} : { children : React . ReactNode } ) {
420+ return < Container padding = "lg" > { children } </ Container > ;
421+ }
422+
423+ function ChartFooter ( { detector} : { detector : MetricDetector } ) {
424+ return (
425+ < Flex justify = "end" padding = "lg" borderTop = "muted" >
426+ < OpenInButton detector = { detector } />
427+ </ Flex >
428+ ) ;
429+ }
430+
373431export function MetricDetectorDetailsChart ( { detector} : MetricDetectorDetailsChartProps ) {
374432 const location = useLocation ( ) ;
433+ const organization = useOrganization ( ) ;
375434 const dateParams = normalizeDateTimeParams ( location . query ) ;
376435
436+ const destination = getDetectorOpenInDestination ( {
437+ detector,
438+ organization,
439+ statsPeriod : decodeScalar ( location . query . statsPeriod ) ,
440+ start : decodeScalar ( location . query . start ) ,
441+ end : decodeScalar ( location . query . end ) ,
442+ } ) ;
443+
377444 const { data : openPeriods = [ ] } = useOpenPeriods ( {
378445 detectorId : detector . id ,
379446 ...dateParams ,
@@ -388,47 +455,45 @@ export function MetricDetectorDetailsChart({detector}: MetricDetectorDetailsChar
388455
389456 if ( isLoading ) {
390457 return (
391- < Flex height = { CHART_HEIGHT } justify = "center" align = "center" >
392- < Placeholder height = { `${ CHART_HEIGHT } px` } />
393- </ Flex >
458+ < ChartContainer >
459+ < ChartBody >
460+ < Flex height = { CHART_HEIGHT } justify = "center" align = "center" >
461+ < Placeholder height = { `${ CHART_HEIGHT } px` } />
462+ </ Flex >
463+ </ ChartBody >
464+ { destination && < ChartFooter detector = { detector } /> }
465+ </ ChartContainer >
394466 ) ;
395467 }
396468 if ( error || ! chartProps ) {
397469 const errorMessage =
398470 typeof error ?. responseJSON ?. detail === 'string' ? error . responseJSON . detail : null ;
399471 return (
400- < ChartContainer style = { { overflow : ' hidden' } } >
472+ < ChartContainer overflow = " hidden" >
401473 { errorMessage && (
402474 < Alert system type = "error" >
403475 { errorMessage }
404476 </ Alert >
405477 ) }
406- < ChartContainerBody >
478+ < ChartBody >
407479 < Flex justify = "center" align = "center" >
408480 < ErrorPanel height = { `${ CHART_HEIGHT - 45 } px` } >
409481 < IconWarning color = "gray300" size = "lg" />
410482 < div > { t ( 'Error loading chart data' ) } </ div >
411483 </ ErrorPanel >
412484 </ Flex >
413- </ ChartContainerBody >
485+ </ ChartBody >
486+ { destination && < ChartFooter detector = { detector } /> }
414487 </ ChartContainer >
415488 ) ;
416489 }
417490
418491 return (
419492 < ChartContainer >
420- < ChartContainerBody >
493+ < ChartBody >
421494 < AreaChart { ...chartProps } />
422- </ ChartContainerBody >
495+ </ ChartBody >
496+ { destination && < ChartFooter detector = { detector } /> }
423497 </ ChartContainer >
424498 ) ;
425499}
426-
427- const ChartContainer = styled ( 'div' ) `
428- border: 1px solid ${ p => p . theme . border } ;
429- border-radius: ${ p => p . theme . borderRadius } ;
430- ` ;
431-
432- const ChartContainerBody = styled ( 'div' ) `
433- padding: ${ p => p . theme . space . xs } ${ p => p . theme . space . lg } ${ p => p . theme . space . xs } ;
434- ` ;
0 commit comments