useHasFirstSpan.tsx 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import type {Project} from 'sentry/types/project';
  2. import {isActiveSuperuser} from 'sentry/utils/isActiveSuperuser';
  3. import usePageFilters from 'sentry/utils/usePageFilters';
  4. import useProjects from 'sentry/utils/useProjects';
  5. import {ModuleName} from 'sentry/views/insights/types';
  6. const excludedModuleNames = [
  7. ModuleName.OTHER,
  8. ModuleName.MOBILE_UI,
  9. ModuleName.MOBILE_SCREENS,
  10. ModuleName.CRONS,
  11. ModuleName.UPTIME,
  12. ] as const;
  13. type ExcludedModuleNames = (typeof excludedModuleNames)[number];
  14. const modulePropertyMap: Record<
  15. Exclude<ModuleName, ExcludedModuleNames>,
  16. keyof Project
  17. > = {
  18. [ModuleName.HTTP]: 'hasInsightsHttp',
  19. [ModuleName.DB]: 'hasInsightsDb',
  20. [ModuleName.CACHE]: 'hasInsightsCaches',
  21. [ModuleName.VITAL]: 'hasInsightsVitals',
  22. [ModuleName.QUEUE]: 'hasInsightsQueues',
  23. [ModuleName.SCREEN_LOAD]: 'hasInsightsScreenLoad',
  24. [ModuleName.APP_START]: 'hasInsightsAppStart',
  25. // Renamed resource to assets
  26. [ModuleName.RESOURCE]: 'hasInsightsAssets',
  27. [ModuleName.AI]: 'hasInsightsLlmMonitoring',
  28. [ModuleName.SCREEN_RENDERING]: 'hasInsightsScreenLoad', // Screen rendering and screen loads share similar spans
  29. };
  30. /**
  31. * Returns whether the module and current project selection has received a first insight span
  32. * @param module The name of the module that will be checked for a first span
  33. * @param projects The projects to check for the first span. If not provided, the selected projects will be used
  34. * @returns true if the module has a first span in the selected projects, false otherwise
  35. */
  36. export function useHasFirstSpan(module: ModuleName, projects?: Project[]): boolean {
  37. const {projects: allProjects} = useProjects();
  38. const pageFilters = usePageFilters();
  39. // Unsupported modules. Remove MOBILE_UI from this list once released.
  40. if ((excludedModuleNames as readonly ModuleName[]).includes(module)) {
  41. return false;
  42. }
  43. if (projects) {
  44. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  45. return projects.some(p => p[modulePropertyMap[module]] === true);
  46. }
  47. let selectedProjects: Project[] = [];
  48. // There are three cases for the selected pageFilter projects:
  49. // - [] empty list represents "My Projects"
  50. // - [-1] represents "All Projects"
  51. // - [.., ..] otherwise, represents a list of project IDs
  52. if (pageFilters.selection.projects.length === 0 && isActiveSuperuser()) {
  53. selectedProjects = allProjects; // when superuser is enabled, My Projects isn't applicable, and in reality all projects are selected when projects.length === 0
  54. }
  55. if (pageFilters.selection.projects.length === 0) {
  56. selectedProjects = allProjects.filter(p => p.isMember);
  57. } else if (
  58. pageFilters.selection.projects.length === 1 &&
  59. pageFilters.selection.projects[0] === -1
  60. ) {
  61. selectedProjects = allProjects;
  62. } else {
  63. selectedProjects = allProjects.filter(p =>
  64. pageFilters.selection.projects.includes(parseInt(p.id, 10))
  65. );
  66. }
  67. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  68. return selectedProjects.some(p => p[modulePropertyMap[module]] === true);
  69. }