header.tsx 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import isPropValid from '@emotion/is-prop-valid';
  2. import styled from '@emotion/styled';
  3. import Breadcrumbs from 'sentry/components/breadcrumbs';
  4. import {Button} from 'sentry/components/button';
  5. import ButtonBar from 'sentry/components/buttonBar';
  6. import IdBadge from 'sentry/components/idBadge';
  7. import * as Layout from 'sentry/components/layouts/thirds';
  8. import {IconCopy, IconEdit} from 'sentry/icons';
  9. import {t} from 'sentry/locale';
  10. import {Organization, Project} from 'sentry/types';
  11. import {MetricRule} from 'sentry/views/alerts/rules/metric/types';
  12. import {isIssueAlert} from '../../../utils';
  13. type Props = {
  14. hasMetricRuleDetailsError: boolean;
  15. organization: Organization;
  16. project?: Project;
  17. rule?: MetricRule;
  18. };
  19. function DetailsHeader({hasMetricRuleDetailsError, rule, organization, project}: Props) {
  20. const isRuleReady = !!rule && !hasMetricRuleDetailsError;
  21. const ruleTitle = rule && !hasMetricRuleDetailsError ? rule.name : '';
  22. const settingsLink =
  23. rule &&
  24. `/organizations/${organization.slug}/alerts/${
  25. isIssueAlert(rule) ? 'rules' : 'metric-rules'
  26. }/${project?.slug ?? rule?.projects?.[0]}/${rule.id}/`;
  27. const duplicateLink = {
  28. pathname: `/organizations/${organization.slug}/alerts/new/metric/`,
  29. query: {
  30. project: project?.slug,
  31. duplicateRuleId: rule?.id,
  32. createFromDuplicate: true,
  33. referrer: 'metric_rule_details',
  34. },
  35. };
  36. return (
  37. <Layout.Header>
  38. <Layout.HeaderContent>
  39. <Breadcrumbs
  40. crumbs={[
  41. {label: t('Alerts'), to: `/organizations/${organization.slug}/alerts/rules/`},
  42. {label: ruleTitle},
  43. ]}
  44. />
  45. <RuleTitle data-test-id="incident-rule-title" loading={!isRuleReady}>
  46. {project && (
  47. <IdBadge
  48. project={project}
  49. avatarSize={28}
  50. hideName
  51. avatarProps={{hasTooltip: true, tooltip: project.slug}}
  52. />
  53. )}
  54. {ruleTitle}
  55. </RuleTitle>
  56. </Layout.HeaderContent>
  57. <Layout.HeaderActions>
  58. <ButtonBar gap={1}>
  59. <Button size="sm" icon={<IconCopy />} to={duplicateLink}>
  60. {t('Duplicate')}
  61. </Button>
  62. <Button size="sm" icon={<IconEdit />} to={settingsLink}>
  63. {t('Edit Rule')}
  64. </Button>
  65. </ButtonBar>
  66. </Layout.HeaderActions>
  67. </Layout.Header>
  68. );
  69. }
  70. export default DetailsHeader;
  71. const RuleTitle = styled(Layout.Title, {
  72. shouldForwardProp: p => typeof p === 'string' && isPropValid(p) && p !== 'loading',
  73. })<{loading: boolean}>`
  74. ${p => p.loading && 'opacity: 0'};
  75. `;