Skip to content

Commit b4c922f

Browse files
authored
feat(aci): Add metric detector chart to details (#95574)
1 parent 8a69b28 commit b4c922f

File tree

6 files changed

+112
-54
lines changed

6 files changed

+112
-54
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import styled from '@emotion/styled';
2+
3+
import type {MetricDetector} from 'sentry/types/workflowEngine/detectors';
4+
import {MetricDetectorChart} from 'sentry/views/detectors/components/forms/metric/metricDetectorChart';
5+
import {getDetectorDataset} from 'sentry/views/detectors/components/forms/metric/metricFormData';
6+
7+
interface MetricDetectorDetailsChartProps {
8+
detector: MetricDetector;
9+
}
10+
11+
export function MetricDetectorDetailsChart({detector}: MetricDetectorDetailsChartProps) {
12+
const dataSource = detector.dataSources[0];
13+
const snubaQuery =
14+
dataSource?.type === 'snuba_query_subscription'
15+
? dataSource.queryObj?.snubaQuery
16+
: undefined;
17+
18+
if (!snubaQuery) {
19+
// Unlikely, helps narrow types
20+
return null;
21+
}
22+
23+
const dataset = getDetectorDataset(snubaQuery.dataset, snubaQuery.eventTypes);
24+
const aggregate = snubaQuery.aggregate;
25+
const query = snubaQuery.query;
26+
const environment = snubaQuery.environment;
27+
const interval = snubaQuery.timeWindow;
28+
const conditions = detector.conditionGroup?.conditions || [];
29+
const detectionType = detector.config.detectionType;
30+
31+
return (
32+
<ChartContainer>
33+
<MetricDetectorChart
34+
dataset={dataset}
35+
aggregate={aggregate}
36+
interval={interval}
37+
query={query}
38+
environment={environment}
39+
projectId={detector.projectId}
40+
conditions={conditions}
41+
detectionType={detectionType}
42+
/>
43+
</ChartContainer>
44+
);
45+
}
46+
47+
const ChartContainer = styled('div')`
48+
padding: ${p => p.theme.space.xs} ${p => p.theme.space.lg} ${p => p.theme.space.md};
49+
border: 1px solid ${p => p.theme.border};
50+
border-radius: ${p => p.theme.borderRadius};
51+
`;

static/app/views/detectors/components/details/metric/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {MetricDetector} from 'sentry/types/workflowEngine/detectors';
44
import {DetectorDetailsAutomations} from 'sentry/views/detectors/components/details/common/automations';
55
import {DetectorDetailsHeader} from 'sentry/views/detectors/components/details/common/header';
66
import {DetectorDetailsOngoingIssues} from 'sentry/views/detectors/components/details/common/ongoingIssues';
7+
import {MetricDetectorDetailsChart} from 'sentry/views/detectors/components/details/metric/chart';
78
import {MetricDetectorDetailsSidebar} from 'sentry/views/detectors/components/details/metric/sidebar';
89

910
type MetricDetectorDetailsProps = {
@@ -17,6 +18,7 @@ export function MetricDetectorDetails({detector, project}: MetricDetectorDetails
1718
<DetectorDetailsHeader detector={detector} project={project} />
1819
<DetailLayout.Body>
1920
<DetailLayout.Main>
21+
<MetricDetectorDetailsChart detector={detector} />
2022
<DetectorDetailsOngoingIssues />
2123
<DetectorDetailsAutomations detector={detector} />
2224
</DetailLayout.Main>

static/app/views/detectors/components/forms/metric/metricDetectorChart.tsx

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {useMemo} from 'react';
2-
import styled from '@emotion/styled';
32

43
import {AreaChart} from 'sentry/components/charts/areaChart';
54
import ErrorPanel from 'sentry/components/charts/errorPanel';
@@ -14,7 +13,7 @@ import type {DetectorDataset} from 'sentry/views/detectors/components/forms/metr
1413
import {useMetricDetectorSeries} from 'sentry/views/detectors/hooks/useMetricDetectorSeries';
1514
import {useMetricDetectorThresholdSeries} from 'sentry/views/detectors/hooks/useMetricDetectorThresholdSeries';
1615

17-
const CHART_HEIGHT = 150;
16+
const CHART_HEIGHT = 165;
1817

1918
interface MetricDetectorChartProps {
2019
/**
@@ -104,55 +103,44 @@ export function MetricDetectorChart({
104103

105104
if (isPending) {
106105
return (
107-
<ChartContainer>
108-
<Flex style={{height: CHART_HEIGHT}} justify="center" align="center">
109-
<Placeholder height={`${CHART_HEIGHT - 20}px`} />
110-
</Flex>
111-
</ChartContainer>
106+
<Flex style={{height: CHART_HEIGHT}} justify="center" align="center">
107+
<Placeholder height={`${CHART_HEIGHT - 20}px`} />
108+
</Flex>
112109
);
113110
}
114111

115112
if (isError) {
116113
return (
117-
<ChartContainer>
118-
<Flex style={{height: CHART_HEIGHT}} justify="center" align="center">
119-
<ErrorPanel>
120-
<IconWarning color="gray300" size="lg" />
121-
<div>{t('Error loading chart data')}</div>
122-
</ErrorPanel>
123-
</Flex>
124-
</ChartContainer>
114+
<Flex style={{height: CHART_HEIGHT}} justify="center" align="center">
115+
<ErrorPanel>
116+
<IconWarning color="gray300" size="lg" />
117+
<div>{t('Error loading chart data')}</div>
118+
</ErrorPanel>
119+
</Flex>
125120
);
126121
}
127122

128123
return (
129-
<ChartContainer>
130-
<AreaChart
131-
isGroupedByDate
132-
showTimeInTooltip
133-
height={CHART_HEIGHT}
134-
stacked={false}
135-
series={mergedSeries}
136-
yAxis={{
137-
min: yAxisBounds.min,
138-
max: yAxisBounds.max,
139-
axisLabel: {
140-
// Hide the maximum y-axis label to avoid showing arbitrary threshold values
141-
showMaxLabel: false,
142-
},
143-
}}
144-
grid={{
145-
left: space(0.25),
146-
right: space(0.5),
147-
top: space(1),
148-
bottom: space(1),
149-
}}
150-
/>
151-
</ChartContainer>
124+
<AreaChart
125+
isGroupedByDate
126+
showTimeInTooltip
127+
height={CHART_HEIGHT}
128+
stacked={false}
129+
series={mergedSeries}
130+
yAxis={{
131+
min: yAxisBounds.min,
132+
max: yAxisBounds.max,
133+
axisLabel: {
134+
// Hide the maximum y-axis label to avoid showing arbitrary threshold values
135+
showMaxLabel: false,
136+
},
137+
}}
138+
grid={{
139+
left: space(0.25),
140+
right: space(0.5),
141+
top: space(0.5),
142+
bottom: space(1),
143+
}}
144+
/>
152145
);
153146
}
154-
155-
const ChartContainer = styled('div')`
156-
max-width: 1440px;
157-
border-top: 1px solid ${p => p.theme.border};
158-
`;

static/app/views/detectors/components/forms/metric/metricFormData.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ export function createConditions(
223223
/**
224224
* Convert backend dataset to our form dataset
225225
*/
226-
const getDetectorDataset = (
226+
export const getDetectorDataset = (
227227
backendDataset: Dataset,
228228
eventTypes: EventTypes[]
229229
): DetectorDataset => {

static/app/views/detectors/components/forms/metric/previewChart.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {useMemo} from 'react';
2+
import styled from '@emotion/styled';
23

34
import {MetricDetectorChart} from 'sentry/views/detectors/components/forms/metric/metricDetectorChart';
45
import {
@@ -49,15 +50,22 @@ export function MetricDetectorPreviewChart() {
4950
}, [conditionType, conditionValue, initialPriorityLevel, highThreshold, kind]);
5051

5152
return (
52-
<MetricDetectorChart
53-
dataset={dataset}
54-
aggregate={aggregateFunction}
55-
interval={interval}
56-
query={query}
57-
environment={environment}
58-
projectId={projectId}
59-
conditions={conditions}
60-
detectionType={kind}
61-
/>
53+
<ChartContainer>
54+
<MetricDetectorChart
55+
dataset={dataset}
56+
aggregate={aggregateFunction}
57+
interval={interval}
58+
query={query}
59+
environment={environment}
60+
projectId={projectId}
61+
conditions={conditions}
62+
detectionType={kind}
63+
/>
64+
</ChartContainer>
6265
);
6366
}
67+
68+
const ChartContainer = styled('div')`
69+
max-width: 1440px;
70+
border-top: 1px solid ${p => p.theme.border};
71+
`;

static/app/views/detectors/detail.spec.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ describe('DetectorDetails', function () {
6161
url: `/organizations/${organization.slug}/users/1/`,
6262
body: UserFixture(),
6363
});
64+
MockApiClient.addMockResponse({
65+
url: `/organizations/${organization.slug}/events-stats/`,
66+
body: {
67+
data: [
68+
[1543449600, [20, 12]],
69+
[1543449601, [10, 5]],
70+
],
71+
},
72+
});
6473
});
6574

6675
it('renders the detector details and snuba query', async function () {

0 commit comments

Comments
 (0)