metricHistory.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import {useMemo} from 'react';
  2. import {css} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import CollapsePanel from 'sentry/components/collapsePanel';
  5. import {PanelTable} from 'sentry/components/panels/panelTable';
  6. import {t, tn} from 'sentry/locale';
  7. import {space} from 'sentry/styles/space';
  8. import type {ActivationTriggerActivity, AlertRuleActivation} from 'sentry/types/alerts';
  9. import {ActivationTrigger} from 'sentry/types/alerts';
  10. import useOrganization from 'sentry/utils/useOrganization';
  11. import MetricAlertActivity from 'sentry/views/alerts/rules/metric/details/metricActivity';
  12. import MetricHistoryActivation from 'sentry/views/alerts/rules/metric/details/metricHistoryActivation';
  13. import type {Incident} from 'sentry/views/alerts/types';
  14. const COLLAPSE_COUNT = 3;
  15. type Props = {
  16. activations?: AlertRuleActivation[];
  17. incidents?: Incident[];
  18. };
  19. function MetricHistory({incidents, activations}: Props) {
  20. const organization = useOrganization();
  21. const sortedActivity = useMemo(() => {
  22. const filteredIncidents = (incidents ?? []).filter(
  23. incident => incident.activities?.length
  24. );
  25. const activationTriggers: ActivationTriggerActivity[] = [];
  26. activations?.forEach(activation => {
  27. activationTriggers.push({
  28. type: ActivationTrigger.ACTIVATED,
  29. activator: activation.activator,
  30. conditionType: activation.conditionType,
  31. dateCreated: activation.dateCreated,
  32. });
  33. if (activation.isComplete) {
  34. activationTriggers.push({
  35. type: ActivationTrigger.FINISHED,
  36. activator: activation.activator,
  37. conditionType: activation.conditionType,
  38. dateCreated: activation.finishedAt,
  39. });
  40. }
  41. });
  42. return [...filteredIncidents, ...activationTriggers].sort((a, b) =>
  43. a.dateCreated > b.dateCreated ? -1 : 1
  44. );
  45. }, [incidents, activations]);
  46. const numOfActivities = sortedActivity.length;
  47. return (
  48. <CollapsePanel
  49. items={numOfActivities}
  50. collapseCount={COLLAPSE_COUNT}
  51. disableBorder={false}
  52. buttonTitle={tn('Hidden Alert', 'Hidden Alerts', numOfActivities - COLLAPSE_COUNT)}
  53. >
  54. {({isExpanded, showMoreButton}) => (
  55. <div>
  56. <StyledPanelTable
  57. headers={[t('Alert'), t('Reason'), t('Duration'), t('Date Triggered')]}
  58. isEmpty={!numOfActivities}
  59. emptyMessage={t('No alerts triggered during this time.')}
  60. expanded={numOfActivities <= COLLAPSE_COUNT || isExpanded}
  61. data-test-id={'history-table'}
  62. >
  63. {sortedActivity.map((item, idx) => {
  64. if (idx >= COLLAPSE_COUNT && !isExpanded) {
  65. return null;
  66. }
  67. if ('activator' in item) {
  68. return (
  69. <MetricHistoryActivation
  70. key={`${item.type}-${item.activator}`}
  71. activationActivity={item}
  72. organization={organization}
  73. />
  74. );
  75. }
  76. return (
  77. <MetricAlertActivity
  78. key={idx}
  79. incident={item}
  80. organization={organization}
  81. />
  82. );
  83. })}
  84. </StyledPanelTable>
  85. {showMoreButton}
  86. </div>
  87. )}
  88. </CollapsePanel>
  89. );
  90. }
  91. export default MetricHistory;
  92. const StyledPanelTable = styled(PanelTable)<{expanded: boolean; isEmpty: boolean}>`
  93. grid-template-columns: max-content 1fr repeat(2, max-content);
  94. & > div {
  95. padding: ${space(1)} ${space(2)};
  96. }
  97. div:last-of-type {
  98. padding: ${p => p.isEmpty && `48px ${space(1)}`};
  99. }
  100. ${p =>
  101. !p.expanded &&
  102. css`
  103. margin-bottom: 0px;
  104. border-bottom-left-radius: 0px;
  105. border-bottom-right-radius: 0px;
  106. border-bottom: none;
  107. `}
  108. `;