noDataMessage.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import {Fragment} from 'react';
  2. import sumBy from 'lodash/sumBy';
  3. import ExternalLink from 'sentry/components/links/externalLink';
  4. import {t, tct} from 'sentry/locale';
  5. import useOrganization from 'sentry/utils/useOrganization';
  6. import usePageFilters from 'sentry/utils/usePageFilters';
  7. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  8. import {useIneligibleProjects} from 'sentry/views/performance/database/useIneligibleProjects';
  9. import {useProjectSpanMetricCounts} from 'sentry/views/starfish/queries/useProjectSpanMetricsCounts';
  10. interface Props {
  11. Wrapper?: React.ComponentType;
  12. }
  13. function DivWrapper(props) {
  14. return <div {...props} />;
  15. }
  16. export function NoDataMessage({Wrapper = DivWrapper}: Props) {
  17. const {selection, isReady: pageFilterIsReady} = usePageFilters();
  18. const selectedProjectIds = selection.projects.map(projectId => projectId.toString());
  19. const {data: projectSpanMetricsCounts} = useProjectSpanMetricCounts({
  20. query: 'span.module:db',
  21. statsPeriod: SAMPLE_STATS_PERIOD,
  22. enabled: pageFilterIsReady,
  23. projectId: selectedProjectIds,
  24. });
  25. const doesAnySelectedProjectHaveMetrics =
  26. sumBy(projectSpanMetricsCounts, 'count()') > 0;
  27. const {ineligibleProjects} = useIneligibleProjects({
  28. projectId: selectedProjectIds,
  29. enabled: pageFilterIsReady && !doesAnySelectedProjectHaveMetrics,
  30. });
  31. const organization = useOrganization();
  32. const hasMoreIneligibleProjectsThanVisible =
  33. ineligibleProjects.length > MAX_LISTED_PROJECTS;
  34. if (!projectSpanMetricsCounts) {
  35. return null;
  36. }
  37. if (doesAnySelectedProjectHaveMetrics) {
  38. return null;
  39. }
  40. const firstIneligibleProjects = ineligibleProjects.slice(0, MAX_LISTED_PROJECTS + 1);
  41. return (
  42. <Wrapper>
  43. {t('No queries found.')}{' '}
  44. {tct(
  45. 'Try updating your filters, or learn more about performance monitoring for queries in our [documentation:documentation].',
  46. {
  47. documentation: (
  48. <ExternalLink href="https://docs.sentry.io/product/performance/queries/" />
  49. ),
  50. }
  51. )}{' '}
  52. {ineligibleProjects.length > 0 &&
  53. tct('You may also be missing data due to outdated SDKs: [projectList]', {
  54. documentation: (
  55. <ExternalLink href="https://docs.sentry.io/product/performance/query-insights/" />
  56. ),
  57. projectList: (
  58. <Fragment>
  59. {firstIneligibleProjects.map((project, projectIndex) => {
  60. return (
  61. <span key={project.id}>
  62. <a
  63. href={normalizeUrl(
  64. `/organizations/${organization.slug}/projects/${project.slug}/`
  65. )}
  66. >
  67. {project.name}
  68. </a>
  69. {projectIndex < firstIneligibleProjects.length - 1 && ', '}
  70. </span>
  71. );
  72. })}
  73. </Fragment>
  74. ),
  75. })}
  76. {hasMoreIneligibleProjectsThanVisible &&
  77. tct(' and [count] more.', {
  78. count: ineligibleProjects.length - MAX_LISTED_PROJECTS,
  79. })}{' '}
  80. </Wrapper>
  81. );
  82. }
  83. const MAX_LISTED_PROJECTS = 3;
  84. const SAMPLE_STATS_PERIOD = '14d'; // The time period in which to check for any presence of span metrics