123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- import styled from '@emotion/styled';
- import {AreaChart} from 'sentry/components/charts/areaChart';
- import ChartZoom from 'sentry/components/charts/chartZoom';
- import {HeaderTitleLegend, SectionHeading} from 'sentry/components/charts/styles';
- import type {DateTimeObject} from 'sentry/components/charts/utils';
- import Panel from 'sentry/components/panels/panel';
- import PanelBody from 'sentry/components/panels/panelBody';
- import PanelFooter from 'sentry/components/panels/panelFooter';
- import Placeholder from 'sentry/components/placeholder';
- import {t} from 'sentry/locale';
- import {space} from 'sentry/styles/space';
- import type {IssueAlertRule, ProjectAlertRuleStats} from 'sentry/types/alerts';
- import type {Project} from 'sentry/types/project';
- import getDynamicText from 'sentry/utils/getDynamicText';
- import {useApiQuery} from 'sentry/utils/queryClient';
- import useOrganization from 'sentry/utils/useOrganization';
- import useRouter from 'sentry/utils/useRouter';
- import RouteError from 'sentry/views/routeError';
- interface IssueAlertDetailsProps extends DateTimeObject {
- project: Project;
- rule: IssueAlertRule;
- }
- export function IssueAlertDetailsChart({
- project,
- period,
- start,
- end,
- utc,
- rule,
- }: IssueAlertDetailsProps) {
- const organization = useOrganization();
- const router = useRouter();
- const {
- data: ruleFireHistory,
- isLoading,
- isError,
- error,
- } = useApiQuery<ProjectAlertRuleStats[]>(
- [
- `/projects/${organization.slug}/${project.slug}/rules/${rule.id}/stats/`,
- {
- query: {
- ...(period && {statsPeriod: period}),
- start,
- end,
- utc,
- },
- },
- ],
- {staleTime: 30000}
- );
- const totalAlertsTriggered =
- ruleFireHistory?.reduce((acc, curr) => acc + curr.count, 0) ?? 0;
- if (isError) {
- return <RouteError error={error} />;
- }
- return (
- <Panel>
- <StyledPanelBody withPadding>
- <ChartHeader>
- <HeaderTitleLegend>{t('Alerts Triggered')}</HeaderTitleLegend>
- </ChartHeader>
- {getDynamicText({
- value: isLoading ? (
- <Placeholder height="200px" />
- ) : (
- <ChartZoom
- router={router}
- period={period}
- start={start}
- end={end}
- utc={utc}
- usePageDate
- >
- {zoomRenderProps => (
- <AreaChart
- {...zoomRenderProps}
- isGroupedByDate
- showTimeInTooltip
- grid={{
- left: space(0.25),
- right: space(2),
- top: space(3),
- bottom: 0,
- }}
- yAxis={{
- minInterval: 1,
- }}
- series={[
- {
- seriesName: 'Alerts Triggered',
- data:
- ruleFireHistory?.map(alert => ({
- name: alert.date,
- value: alert.count,
- })) ?? [],
- emphasis: {
- disabled: true,
- },
- },
- ]}
- />
- )}
- </ChartZoom>
- ),
- fixed: <Placeholder height="200px" testId="skeleton-ui" />,
- })}
- </StyledPanelBody>
- <ChartFooter>
- <FooterHeader>{t('Total Alerts')}</FooterHeader>
- <FooterValue>
- {isLoading ? (
- <Placeholder height="16px" width="50px" />
- ) : (
- totalAlertsTriggered.toLocaleString()
- )}
- </FooterValue>
- </ChartFooter>
- </Panel>
- );
- }
- const ChartHeader = styled('div')`
- margin-bottom: ${space(3)};
- `;
- const ChartFooter = styled(PanelFooter)`
- display: flex;
- align-items: center;
- padding: ${space(1)} 20px;
- `;
- const FooterHeader = styled(SectionHeading)`
- display: flex;
- align-items: center;
- margin: 0;
- font-weight: bold;
- font-size: ${p => p.theme.fontSizeMedium};
- line-height: 1;
- `;
- const FooterValue = styled('div')`
- display: flex;
- align-items: center;
- margin: 0 ${space(1)};
- `;
- /* Override padding to make chart appear centered */
- const StyledPanelBody = styled(PanelBody)`
- padding-right: 6px;
- `;
|