monitorIssues.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import {Fragment, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import {LinkButton} from 'sentry/components/button';
  4. import EmptyStateWarning from 'sentry/components/emptyStateWarning';
  5. import GroupList from 'sentry/components/issues/groupList';
  6. import Panel from 'sentry/components/panels/panel';
  7. import PanelBody from 'sentry/components/panels/panelBody';
  8. import {SegmentedControl} from 'sentry/components/segmentedControl';
  9. import {t} from 'sentry/locale';
  10. import {space} from 'sentry/styles/space';
  11. import {getUtcDateString} from 'sentry/utils/dates';
  12. import usePageFilters from 'sentry/utils/usePageFilters';
  13. import type {Monitor, MonitorEnvironment} from '../types';
  14. enum IssuesType {
  15. ALL = 'all',
  16. UNRESOLVED = 'unresolved',
  17. }
  18. const ISSUE_TYPES = [
  19. {value: IssuesType.UNRESOLVED, label: t('Unresolved Issues')},
  20. {value: IssuesType.ALL, label: t('All Issues')},
  21. ];
  22. type Props = {
  23. monitor: Monitor;
  24. monitorEnvs: MonitorEnvironment[];
  25. orgSlug: string;
  26. };
  27. function MonitorIssuesEmptyMessage() {
  28. return (
  29. <Panel>
  30. <PanelBody>
  31. <EmptyStateWarning>
  32. <p>{t('No issues relating to this cron monitor have been found.')}</p>
  33. </EmptyStateWarning>
  34. </PanelBody>
  35. </Panel>
  36. );
  37. }
  38. function MonitorIssues({orgSlug, monitor, monitorEnvs}: Props) {
  39. const {selection} = usePageFilters();
  40. const {start, end, period} = selection.datetime;
  41. const timeProps =
  42. start && end
  43. ? {
  44. start: getUtcDateString(start),
  45. end: getUtcDateString(end),
  46. }
  47. : {
  48. statsPeriod: period,
  49. };
  50. const [issuesType, setIssuesType] = useState<IssuesType>(IssuesType.UNRESOLVED);
  51. const monitorFilter = `monitor.slug:${monitor.slug}`;
  52. const envFilter = `environment:[${monitorEnvs.map(e => e.name).join(',')}]`;
  53. const issueTypeFilter = issuesType === IssuesType.UNRESOLVED ? 'is:unresolved' : '';
  54. const issueQuery = `${monitorFilter} ${envFilter} ${issueTypeFilter}`;
  55. const issueSearchLocation = {
  56. pathname: `/organizations/${orgSlug}/issues/`,
  57. query: {
  58. query: issueQuery,
  59. project: monitor.project.id,
  60. ...timeProps,
  61. },
  62. };
  63. // TODO(epurkhiser): We probably want to filter on envrionemnt
  64. return (
  65. <Fragment>
  66. <ControlsWrapper>
  67. <SegmentedControl
  68. aria-label={t('Issue category')}
  69. value={issuesType}
  70. size="xs"
  71. onChange={setIssuesType}
  72. >
  73. {ISSUE_TYPES.map(({value, label}) => (
  74. <SegmentedControl.Item key={value} textValue={label}>
  75. {label}
  76. </SegmentedControl.Item>
  77. ))}
  78. </SegmentedControl>
  79. <LinkButton size="xs" to={issueSearchLocation}>
  80. {t('Open In Issues')}
  81. </LinkButton>
  82. </ControlsWrapper>
  83. <GroupList
  84. orgSlug={orgSlug}
  85. endpointPath={`/organizations/${orgSlug}/issues/`}
  86. queryParams={{
  87. query: issueQuery,
  88. project: monitor.project.id,
  89. limit: 20,
  90. ...timeProps,
  91. }}
  92. query=""
  93. renderEmptyMessage={MonitorIssuesEmptyMessage}
  94. canSelectGroups={false}
  95. withPagination={false}
  96. withChart={false}
  97. useTintRow={false}
  98. source="monitors"
  99. />
  100. </Fragment>
  101. );
  102. }
  103. const ControlsWrapper = styled('div')`
  104. display: flex;
  105. align-items: flex-end;
  106. justify-content: space-between;
  107. margin-bottom: ${space(1)};
  108. flex-wrap: wrap;
  109. `;
  110. export default MonitorIssues;