header.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import {RouteComponentProps} from 'react-router';
  2. import isPropValid from '@emotion/is-prop-valid';
  3. import styled from '@emotion/styled';
  4. import Breadcrumbs from 'sentry/components/breadcrumbs';
  5. import Button from 'sentry/components/button';
  6. import IdBadge from 'sentry/components/idBadge';
  7. import PageHeading from 'sentry/components/pageHeading';
  8. import {IconCopy, IconEdit} from 'sentry/icons';
  9. import {t} from 'sentry/locale';
  10. import {PageHeader} from 'sentry/styles/organization';
  11. import space from 'sentry/styles/space';
  12. import {Project} from 'sentry/types';
  13. import {MetricRule} from 'sentry/views/alerts/rules/metric/types';
  14. import {isIssueAlert} from '../../../utils';
  15. type Props = Pick<RouteComponentProps<{orgId: string}, {}>, 'params'> & {
  16. hasMetricRuleDetailsError: boolean;
  17. project?: Project;
  18. rule?: MetricRule;
  19. };
  20. function DetailsHeader({hasMetricRuleDetailsError, rule, params, project}: Props) {
  21. const isRuleReady = !!rule && !hasMetricRuleDetailsError;
  22. const ruleTitle = rule && !hasMetricRuleDetailsError ? rule.name : '';
  23. const settingsLink =
  24. rule &&
  25. `/organizations/${params.orgId}/alerts/${
  26. isIssueAlert(rule) ? 'rules' : 'metric-rules'
  27. }/${project?.slug ?? rule?.projects?.[0]}/${rule.id}/`;
  28. const duplicateLink = {
  29. pathname: `/organizations/${params.orgId}/alerts/new/metric/`,
  30. query: {
  31. project: project?.slug,
  32. duplicateRuleId: rule?.id,
  33. createFromDuplicate: true,
  34. referrer: 'metric_rule_details',
  35. },
  36. };
  37. return (
  38. <Header>
  39. <BreadCrumbBar>
  40. <AlertBreadcrumbs
  41. crumbs={[
  42. {label: t('Alerts'), to: `/organizations/${params.orgId}/alerts/rules/`},
  43. {label: ruleTitle},
  44. ]}
  45. />
  46. <Controls>
  47. <Button size="sm" icon={<IconCopy />} to={duplicateLink}>
  48. {t('Duplicate')}
  49. </Button>
  50. <Button size="sm" icon={<IconEdit />} to={settingsLink}>
  51. {t('Edit Rule')}
  52. </Button>
  53. </Controls>
  54. </BreadCrumbBar>
  55. <Details>
  56. <RuleTitle data-test-id="incident-rule-title" loading={!isRuleReady}>
  57. {project && (
  58. <IdBadge
  59. project={project}
  60. avatarSize={28}
  61. hideName
  62. avatarProps={{hasTooltip: true, tooltip: project.slug}}
  63. />
  64. )}
  65. {ruleTitle}
  66. </RuleTitle>
  67. </Details>
  68. </Header>
  69. );
  70. }
  71. export default DetailsHeader;
  72. const Header = styled('div')`
  73. background-color: ${p => p.theme.backgroundSecondary};
  74. border-bottom: 1px solid ${p => p.theme.border};
  75. `;
  76. const BreadCrumbBar = styled('div')`
  77. display: flex;
  78. margin-bottom: 0;
  79. padding: ${space(2)} ${space(4)} ${space(1)};
  80. `;
  81. const AlertBreadcrumbs = styled(Breadcrumbs)`
  82. flex-grow: 1;
  83. font-size: ${p => p.theme.fontSizeExtraLarge};
  84. padding: 0;
  85. `;
  86. const Controls = styled('div')`
  87. display: grid;
  88. grid-auto-flow: column;
  89. gap: ${space(1)};
  90. `;
  91. const Details = styled(PageHeader)`
  92. margin-bottom: 0;
  93. padding: ${space(1.5)} ${space(4)} ${space(2)};
  94. grid-template-columns: max-content auto;
  95. display: grid;
  96. gap: ${space(3)};
  97. grid-auto-flow: column;
  98. @media (max-width: ${p => p.theme.breakpoints.medium}) {
  99. grid-template-columns: auto;
  100. grid-auto-flow: row;
  101. }
  102. `;
  103. const RuleTitle = styled(PageHeading, {
  104. shouldForwardProp: p => typeof p === 'string' && isPropValid(p) && p !== 'loading',
  105. })<{loading: boolean}>`
  106. ${p => p.loading && 'opacity: 0'};
  107. line-height: 1.5;
  108. display: grid;
  109. grid-template-columns: max-content 1fr;
  110. grid-column-gap: ${space(1)};
  111. align-items: center;
  112. `;