projectQuickLinks.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import styled from '@emotion/styled';
  2. import type {Location} from 'history';
  3. import {SectionHeading} from 'sentry/components/charts/styles';
  4. import GlobalSelectionLink from 'sentry/components/globalSelectionLink';
  5. import {Tooltip} from 'sentry/components/tooltip';
  6. import {IconLink} from 'sentry/icons';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import type {Organization} from 'sentry/types/organization';
  10. import type {Project} from 'sentry/types/project';
  11. import {decodeScalar} from 'sentry/utils/queryString';
  12. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  13. import type {DomainView} from 'sentry/views/insights/pages/useFilters';
  14. import {DEFAULT_MAX_DURATION} from 'sentry/views/performance/trends/utils';
  15. import {
  16. getPerformanceBaseUrl,
  17. getPerformanceTrendsUrl,
  18. platformToDomainView,
  19. } from 'sentry/views/performance/utils';
  20. import {SidebarSection} from './styles';
  21. type Props = {
  22. location: Location;
  23. organization: Organization;
  24. project?: Project;
  25. };
  26. function ProjectQuickLinks({organization, project, location}: Props) {
  27. function getTrendsLink() {
  28. const queryString = decodeScalar(location.query.query);
  29. const conditions = new MutableSearch(queryString || '');
  30. conditions.setFilterValues('tpm()', ['>0.01']);
  31. conditions.setFilterValues('transaction.duration', [
  32. '>0',
  33. `<${DEFAULT_MAX_DURATION}`,
  34. ]);
  35. return {
  36. pathname: getPerformanceTrendsUrl(organization),
  37. query: {
  38. project: project?.id,
  39. cursor: undefined,
  40. query: conditions.formatString(),
  41. },
  42. };
  43. }
  44. const hasPerfLandingRemovalFlag = organization.features?.includes(
  45. 'insights-performance-landing-removal'
  46. );
  47. const domainView: DomainView | undefined = project
  48. ? platformToDomainView([project], [parseInt(project.id, 10)])
  49. : 'backend';
  50. const quickLinks = [
  51. {
  52. title: t('User Feedback'),
  53. to: {
  54. pathname: `/organizations/${organization.slug}/user-feedback/`,
  55. query: {project: project?.id},
  56. },
  57. },
  58. {
  59. title: t('View Transactions'),
  60. to: {
  61. pathname: hasPerfLandingRemovalFlag
  62. ? `${getPerformanceBaseUrl(organization.slug, domainView)}/`
  63. : `${getPerformanceBaseUrl(organization.slug)}/`,
  64. query: {project: project?.id},
  65. },
  66. disabled: !organization.features.includes('performance-view'),
  67. },
  68. {
  69. title: t('Most Improved/Regressed Transactions'),
  70. to: getTrendsLink(),
  71. disabled: !organization.features.includes('performance-view'),
  72. },
  73. ];
  74. return (
  75. <SidebarSection>
  76. <SectionHeading>{t('Quick Links')}</SectionHeading>
  77. {quickLinks
  78. // push disabled links to the bottom
  79. .sort((link1, link2) => Number(!!link1.disabled) - Number(!!link2.disabled))
  80. .map(({title, to, disabled}) => (
  81. <div key={title}>
  82. <Tooltip
  83. title={t("You don't have access to this feature")}
  84. disabled={!disabled}
  85. >
  86. <QuickLink to={to} disabled={disabled}>
  87. <IconLink />
  88. <QuickLinkText>{title}</QuickLinkText>
  89. </QuickLink>
  90. </Tooltip>
  91. </div>
  92. ))}
  93. </SidebarSection>
  94. );
  95. }
  96. const QuickLink = styled((p: any) =>
  97. p.disabled ? (
  98. <span className={p.className}>{p.children}</span>
  99. ) : (
  100. <GlobalSelectionLink {...p} />
  101. )
  102. )<{
  103. disabled?: boolean;
  104. }>`
  105. margin-bottom: ${space(1)};
  106. display: grid;
  107. align-items: center;
  108. gap: ${space(1)};
  109. grid-template-columns: auto 1fr;
  110. ${p =>
  111. p.disabled &&
  112. `
  113. color: ${p.theme.gray200};
  114. cursor: not-allowed;
  115. `}
  116. `;
  117. const QuickLinkText = styled('span')`
  118. font-size: ${p => p.theme.fontSizeMedium};
  119. ${p => p.theme.overflowEllipsis}
  120. `;
  121. export default ProjectQuickLinks;