firstLastSeenSection.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import styled from '@emotion/styled';
  2. import {Flex} from 'sentry/components/container/flex';
  3. import SeenInfo from 'sentry/components/group/seenInfo';
  4. import Version from 'sentry/components/version';
  5. import VersionHoverCard from 'sentry/components/versionHoverCard';
  6. import {t, tct} from 'sentry/locale';
  7. import {space} from 'sentry/styles/space';
  8. import type {Group} from 'sentry/types/group';
  9. import type {Project} from 'sentry/types/project';
  10. import type {Release} from 'sentry/types/release';
  11. import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
  12. import {useApiQuery} from 'sentry/utils/queryClient';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. import {useFetchAllEnvsGroupData} from 'sentry/views/issueDetails/groupSidebar';
  15. import {useEnvironmentsFromUrl} from 'sentry/views/issueDetails/utils';
  16. interface GroupRelease {
  17. firstRelease: Release;
  18. lastRelease: Release;
  19. }
  20. export default function FirstLastSeenSection({group}: {group: Group}) {
  21. const organization = useOrganization();
  22. const {project} = group;
  23. const issueTypeConfig = getConfigForIssueType(group, group.project);
  24. const {data: allEnvironments} = useFetchAllEnvsGroupData(organization, group);
  25. const {data: groupReleaseData} = useApiQuery<GroupRelease>(
  26. [`/organizations/${organization.slug}/issues/${group.id}/first-last-release/`],
  27. {
  28. staleTime: 30000,
  29. gcTime: 30000,
  30. }
  31. );
  32. const environments = useEnvironmentsFromUrl();
  33. const lastSeen = issueTypeConfig.useOpenPeriodChecks
  34. ? group.openPeriods?.[0]?.lastChecked ?? group.lastSeen
  35. : group.lastSeen;
  36. const shortEnvironmentLabel =
  37. environments.length > 1
  38. ? t('selected environments')
  39. : environments.length === 1
  40. ? environments[0]
  41. : undefined;
  42. const dateGlobal = issueTypeConfig.useOpenPeriodChecks
  43. ? lastSeen
  44. : allEnvironments?.lastSeen ?? lastSeen;
  45. return (
  46. <Flex column gap={space(0.75)}>
  47. <div>
  48. <Flex gap={space(0.5)}>
  49. <Title>{t('Last seen')}</Title>
  50. <SeenInfo
  51. date={lastSeen}
  52. dateGlobal={dateGlobal}
  53. organization={organization}
  54. projectId={project.id}
  55. projectSlug={project.slug}
  56. environment={shortEnvironmentLabel}
  57. />
  58. </Flex>
  59. <ReleaseText project={group.project} release={groupReleaseData?.lastRelease} />
  60. </div>
  61. <div>
  62. <Flex gap={space(0.5)}>
  63. <Title>{t('First seen')}</Title>
  64. <SeenInfo
  65. date={group.firstSeen}
  66. dateGlobal={allEnvironments?.firstSeen ?? group.firstSeen}
  67. organization={organization}
  68. projectId={project.id}
  69. projectSlug={project.slug}
  70. environment={shortEnvironmentLabel}
  71. />
  72. </Flex>
  73. <ReleaseText project={group.project} release={groupReleaseData?.firstRelease} />
  74. </div>
  75. </Flex>
  76. );
  77. }
  78. function ReleaseText({project, release}: {project: Project; release?: Release}) {
  79. const organization = useOrganization();
  80. if (!release) {
  81. return null;
  82. }
  83. return (
  84. <Subtitle>
  85. {tct('in release [release]', {
  86. release: (
  87. <VersionHoverCard
  88. organization={organization}
  89. projectSlug={project.slug}
  90. releaseVersion={release.version}
  91. >
  92. <ReleaseWrapper>
  93. <Version version={release.version} projectId={project.id} />
  94. </ReleaseWrapper>
  95. </VersionHoverCard>
  96. ),
  97. })}
  98. </Subtitle>
  99. );
  100. }
  101. const ReleaseWrapper = styled('span')`
  102. a {
  103. color: ${p => p.theme.gray300};
  104. text-decoration: underline;
  105. text-decoration-style: dotted;
  106. }
  107. `;
  108. const Title = styled('div')`
  109. font-weight: ${p => p.theme.fontWeightBold};
  110. `;
  111. const Subtitle = styled('div')`
  112. font-size: ${p => p.theme.fontSizeSmall};
  113. color: ${p => p.theme.subText};
  114. `;