openInContextLine.tsx 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import styled from '@emotion/styled';
  2. import ExternalLink from 'sentry/components/links/externalLink';
  3. import SentryAppComponentIcon from 'sentry/components/sentryAppComponentIcon';
  4. import {t} from 'sentry/locale';
  5. import {space} from 'sentry/styles/space';
  6. import {SentryAppComponent} from 'sentry/types';
  7. import {addQueryParamsToExistingUrl} from 'sentry/utils/queryString';
  8. import {recordInteraction} from 'sentry/utils/recordSentryAppInteraction';
  9. type Props = {
  10. components: SentryAppComponent[];
  11. filename: string;
  12. lineNo: number;
  13. };
  14. const OpenInContextLine = ({lineNo, filename, components}: Props) => {
  15. const handleRecordInteraction =
  16. (slug: SentryAppComponent['sentryApp']['slug']) => () => {
  17. recordInteraction(slug, 'sentry_app_component_interacted', {
  18. componentType: 'stacktrace-link',
  19. });
  20. };
  21. const getUrl = (url: SentryAppComponent['schema']['url']) => {
  22. return addQueryParamsToExistingUrl(url, {lineNo, filename});
  23. };
  24. return (
  25. <OpenInContainer columnQuantity={components.length + 1}>
  26. <div>{t('Open this line in')}</div>
  27. {components.map(component => {
  28. const url = getUrl(component.schema.url);
  29. const {slug} = component.sentryApp;
  30. const onClickRecordInteraction = handleRecordInteraction(slug);
  31. return (
  32. <OpenInLink
  33. key={component.uuid}
  34. data-test-id={`stacktrace-link-${slug}`}
  35. href={url}
  36. onClick={onClickRecordInteraction}
  37. onContextMenu={onClickRecordInteraction}
  38. openInNewTab
  39. >
  40. <SentryAppComponentIcon sentryAppComponent={component} />
  41. <OpenInName>{component.sentryApp.name}</OpenInName>
  42. </OpenInLink>
  43. );
  44. })}
  45. </OpenInContainer>
  46. );
  47. };
  48. export {OpenInContextLine};
  49. const OpenInContainer = styled('div')<{columnQuantity: number}>`
  50. position: relative;
  51. z-index: 1;
  52. display: grid;
  53. grid-template-columns: repeat(${p => p.columnQuantity}, max-content);
  54. gap: ${space(1)};
  55. color: ${p => p.theme.subText};
  56. background-color: ${p => p.theme.background};
  57. font-family: ${p => p.theme.text.family};
  58. border-bottom: 1px solid ${p => p.theme.border};
  59. padding: ${space(0.25)} ${space(3)};
  60. box-shadow: ${p => p.theme.dropShadowLight};
  61. text-indent: initial;
  62. overflow: auto;
  63. white-space: nowrap;
  64. `;
  65. const OpenInLink = styled(ExternalLink)`
  66. align-items: center;
  67. grid-template-columns: max-content auto;
  68. gap: ${space(0.75)};
  69. color: ${p => p.theme.gray300};
  70. `;
  71. export const OpenInName = styled('strong')`
  72. color: ${p => p.theme.subText};
  73. font-weight: 700;
  74. `;