noDataMessage.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import {Fragment} from 'react';
  2. import {openHelpSearchModal} from 'sentry/actionCreators/modal';
  3. import {Button} from 'sentry/components/button';
  4. import ExternalLink from 'sentry/components/links/externalLink';
  5. import {t, tct} from 'sentry/locale';
  6. import type {Project} from 'sentry/types/project';
  7. import useOrganization from 'sentry/utils/useOrganization';
  8. import usePageFilters from 'sentry/utils/usePageFilters';
  9. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  10. import {MODULE_DOC_LINK} from 'sentry/views/performance/database/settings';
  11. import {useDenylistedProjects} from 'sentry/views/performance/database/useDenylistedProjects';
  12. import {useOutdatedSDKProjects} from 'sentry/views/performance/database/useOutdatedSDKProjects';
  13. interface Props {
  14. Wrapper?: React.ComponentType<any>;
  15. isDataAvailable?: boolean;
  16. }
  17. function DivWrapper(props) {
  18. return <div {...props} />;
  19. }
  20. export function NoDataMessage({Wrapper = DivWrapper, isDataAvailable}: Props) {
  21. const organization = useOrganization();
  22. const {selection, isReady: pageFilterIsReady} = usePageFilters();
  23. const selectedProjectIds = selection.projects.map(projectId => projectId.toString());
  24. const {projects: outdatedProjects, isFetching: areOutdatedProjectsFetching} =
  25. useOutdatedSDKProjects({
  26. projectId: selectedProjectIds,
  27. enabled: pageFilterIsReady && !isDataAvailable,
  28. });
  29. const {projects: denylistedProjects, isFetching: areDenylistProjectsFetching} =
  30. useDenylistedProjects({
  31. projectId: selectedProjectIds,
  32. });
  33. const isDataFetching = areOutdatedProjectsFetching || areDenylistProjectsFetching;
  34. if (isDataFetching) {
  35. return null;
  36. }
  37. const hasAnyProblematicProjects =
  38. (!areOutdatedProjectsFetching && outdatedProjects.length > 0) ||
  39. (!areDenylistProjectsFetching && denylistedProjects.length > 0);
  40. if (isDataAvailable && !hasAnyProblematicProjects) {
  41. return null;
  42. }
  43. return (
  44. <Wrapper>
  45. {!isDataAvailable &&
  46. tct(
  47. 'No queries found. Try updating your filters, or learn more about performance monitoring for queries in our [documentation:documentation].',
  48. {
  49. documentation: <ExternalLink href={MODULE_DOC_LINK} />,
  50. }
  51. )}{' '}
  52. {outdatedProjects.length > 0 &&
  53. tct('You may be missing data due to outdated SDKs: [projectList].', {
  54. projectList: <ProjectList projects={outdatedProjects} />,
  55. })}{' '}
  56. {denylistedProjects.length > 0 &&
  57. tct(
  58. 'Some of your projects have been omitted from query performance analysis. Please [supportLink]. Omitted projects: [projectList].',
  59. {
  60. supportLink: (
  61. <Button priority="link" onClick={() => openHelpSearchModal({organization})}>
  62. {t('Contact Support')}
  63. </Button>
  64. ),
  65. projectList: <ProjectList projects={denylistedProjects} />,
  66. }
  67. )}
  68. </Wrapper>
  69. );
  70. }
  71. interface ProjectListProps {
  72. projects: Project[];
  73. limit?: number;
  74. }
  75. function ProjectList({projects, limit = MAX_LISTED_PROJECTS}: ProjectListProps) {
  76. const organization = useOrganization();
  77. const visibleProjects = projects.slice(0, limit + 1);
  78. const hasMoreProjectsThanVisible = projects.length > MAX_LISTED_PROJECTS;
  79. return (
  80. <Fragment>
  81. {visibleProjects.slice(0, limit).map((project, projectIndex) => {
  82. return (
  83. <span key={project.id}>
  84. <a
  85. href={normalizeUrl(
  86. `/organizations/${organization.slug}/projects/${project.slug}/`
  87. )}
  88. >
  89. {project.name}
  90. </a>
  91. {projectIndex < visibleProjects.length - 1 && ', '}
  92. </span>
  93. );
  94. })}
  95. {hasMoreProjectsThanVisible &&
  96. tct(' and [count] more.', {
  97. count: projects.length - limit,
  98. })}{' '}
  99. </Fragment>
  100. );
  101. }
  102. const MAX_LISTED_PROJECTS = 3;