issueTrackingSignals.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import {
  2. ExternalIssueComponent,
  3. IntegrationComponent,
  4. PluginActionComponent,
  5. PluginIssueComponent,
  6. SentryAppIssueComponent,
  7. } from 'sentry/components/group/externalIssuesList/types';
  8. import useExternalIssueData from 'sentry/components/group/externalIssuesList/useExternalIssueData';
  9. import {Tooltip} from 'sentry/components/tooltip';
  10. import {IconLink} from 'sentry/icons';
  11. import {t} from 'sentry/locale';
  12. import {Event, Group} from 'sentry/types';
  13. import {getIntegrationIcon} from 'sentry/utils/integrationUtil';
  14. interface Props {
  15. group: Group;
  16. }
  17. function filterLinkedPlugins(actions: ExternalIssueComponent[]) {
  18. // Plugins: need to do some extra logic to detect if the issue is linked,
  19. // by checking if there exists an issue object
  20. const plugins = actions.filter(
  21. a =>
  22. (a.type === 'plugin-issue' || a.type === 'plugin-action') &&
  23. 'issue' in a.props.plugin
  24. );
  25. // Non plugins: can read directly from the `hasLinkedIssue` property
  26. const nonPlugins = actions.filter(
  27. a => a.hasLinkedIssue && !(a.type === 'plugin-issue' || a.type === 'plugin-action')
  28. );
  29. return plugins.concat(nonPlugins);
  30. }
  31. function getPluginNames(pluginIssue: PluginIssueComponent | PluginActionComponent) {
  32. return {
  33. name: pluginIssue.props.plugin.name ?? '',
  34. icon: pluginIssue.props.plugin.slug ?? '',
  35. };
  36. }
  37. function getIntegrationNames(integrationIssue: IntegrationComponent) {
  38. if (!integrationIssue.props.configurations.length) {
  39. return {name: '', icon: ''};
  40. }
  41. return {
  42. name: integrationIssue.props.configurations[0].provider.name ?? '',
  43. icon: integrationIssue.key ?? '',
  44. };
  45. }
  46. function getAppIntegrationNames(integrationIssue: SentryAppIssueComponent) {
  47. return {
  48. name: integrationIssue.props.sentryApp.name,
  49. icon: integrationIssue.key ?? '',
  50. };
  51. }
  52. export default function IssueTrackingSignals({group}: Props) {
  53. const {actions} = useExternalIssueData({
  54. group,
  55. event: {} as Event,
  56. project: group.project,
  57. });
  58. const linkedIssues = filterLinkedPlugins(actions);
  59. if (!linkedIssues.length) {
  60. return null;
  61. }
  62. if (linkedIssues.length > 1) {
  63. return (
  64. <Tooltip
  65. title={t('Linked Tickets: %d', linkedIssues.length)}
  66. containerDisplayMode="flex"
  67. >
  68. <IconLink size="xs" />
  69. </Tooltip>
  70. );
  71. }
  72. const issue = linkedIssues[0];
  73. const {name, icon} = {
  74. 'plugin-issue': getPluginNames,
  75. 'plugin-actions': getPluginNames,
  76. 'integration-issue': getIntegrationNames,
  77. 'sentry-app-issue': getAppIntegrationNames,
  78. }[issue.type](issue) ?? {name: '', icon: undefined};
  79. return (
  80. <Tooltip title={t('Linked %s Issue', name)} containerDisplayMode="flex">
  81. {getIntegrationIcon(icon, 'xs')}
  82. </Tooltip>
  83. );
  84. }