Browse Source

feat(insights): reload projects when missing data (#75358)

Refetch the projects when the user arrives on an Insights Module or the
Performance page with no data.

Users can now directly navigate to the Performance or Insights tabs and
see their data during onboarding, without needing an additional refresh
to synchronize the projects hasData flags.
Kevin Liu 7 months ago
parent
commit
ad88919e91

+ 5 - 0
static/app/components/createAlertButton.spec.tsx

@@ -25,6 +25,7 @@ describe('CreateAlertFromViewButton', () => {
     jest.mocked(useProjects).mockReturnValue({
       projects: [],
       onSearch: jest.fn(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       fetching: false,
       hasMore: null,
@@ -72,6 +73,7 @@ describe('CreateAlertFromViewButton', () => {
     jest.mocked(useProjects).mockReturnValue({
       projects,
       onSearch: jest.fn(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       fetching: false,
       hasMore: null,
@@ -107,6 +109,7 @@ describe('CreateAlertFromViewButton', () => {
     jest.mocked(useProjects).mockReturnValue({
       projects,
       onSearch: jest.fn(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       fetching: false,
       hasMore: null,
@@ -155,6 +158,7 @@ describe('CreateAlertFromViewButton', () => {
     jest.mocked(useProjects).mockReturnValue({
       projects,
       onSearch: jest.fn(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       fetching: false,
       hasMore: null,
@@ -257,6 +261,7 @@ describe('CreateAlertFromViewButton', () => {
     jest.mocked(useProjects).mockReturnValue({
       projects,
       onSearch: jest.fn(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       fetching: false,
       hasMore: null,

+ 1 - 0
static/app/components/events/eventReplay/index.spec.tsx

@@ -135,6 +135,7 @@ describe('EventReplay', function () {
       hasMore: false,
       initiallyLoaded: false,
       onSearch: () => Promise.resolve(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       projects: [project],
     });

+ 1 - 0
static/app/components/events/interfaces/breadcrumbs/breadcrumbs.spec.tsx

@@ -36,6 +36,7 @@ describe('Breadcrumbs', () => {
       hasMore: false,
       initiallyLoaded: false,
       onSearch: () => Promise.resolve(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       projects: [project],
     });

+ 1 - 0
static/app/components/replays/header/errorCounts.spec.tsx

@@ -40,6 +40,7 @@ describe('ErrorCounts', () => {
       hasMore: false,
       initiallyLoaded: true,
       onSearch: () => Promise.resolve(),
+      reloadProjects: jest.fn(),
       placeholders: [],
     });
   });

+ 1 - 0
static/app/utils/replays/hooks/useReplayData.spec.tsx

@@ -29,6 +29,7 @@ jest.mocked(useProjects).mockReturnValue({
   hasMore: false,
   initiallyLoaded: true,
   onSearch: () => Promise.resolve(),
+  reloadProjects: jest.fn(),
   placeholders: [],
 });
 

+ 7 - 1
static/app/utils/useProjects.tsx

@@ -58,6 +58,10 @@ type Result = {
    * The loaded projects list
    */
   projects: Project[];
+  /**
+   * Allows consumers to force refetch project data.
+   */
+  reloadProjects: () => Promise<void>;
 } & Pick<State, 'fetching' | 'hasMore' | 'fetchError' | 'initiallyLoaded'>;
 
 type Options = {
@@ -199,7 +203,8 @@ function useProjects({limit, slugs, orgId: propOrgId}: Options = {}) {
         limit,
       });
 
-      const fetchedProjects = uniqBy([...store.projects, ...results], ({slug}) => slug);
+      // Note the order of uniqBy: we prioritize project data recently fetched over previously cached data
+      const fetchedProjects = uniqBy([...results, ...store.projects], ({slug}) => slug);
       ProjectsStore.loadInitialData(fetchedProjects);
 
       setState(prev => ({
@@ -308,6 +313,7 @@ function useProjects({limit, slugs, orgId: propOrgId}: Options = {}) {
     fetchError,
     hasMore,
     onSearch: handleSearch,
+    reloadProjects: loadProjectsBySlug,
   };
 
   return result;

+ 1 - 0
static/app/views/insights/browser/resources/views/resourcesLandingPage.spec.tsx

@@ -168,6 +168,7 @@ const setupMocks = () => {
     initiallyLoaded: true,
     projects: [ProjectFixture({hasInsightsAssets: true})],
     onSearch: jest.fn(),
+    reloadProjects: jest.fn(),
     placeholders: [],
   });
 };

+ 1 - 0
static/app/views/insights/browser/webVitals/components/tables/pagePerformanceTable.spec.tsx

@@ -60,6 +60,7 @@ describe('PagePerformanceTable', function () {
         }),
       ],
       onSearch: jest.fn(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       fetching: false,
       hasMore: null,

+ 1 - 0
static/app/views/insights/browser/webVitals/views/webVitalsLandingPage.spec.tsx

@@ -26,6 +26,7 @@ describe('WebVitalsLandingPage', function () {
     jest.mocked(useProjects).mockReturnValue({
       projects: [ProjectFixture({hasInsightsVitals: true})],
       onSearch: jest.fn(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       fetching: false,
       hasMore: null,

+ 2 - 0
static/app/views/insights/cache/views/cacheLandingPage.spec.tsx

@@ -71,6 +71,7 @@ describe('CacheLandingPage', function () {
       }),
     ],
     onSearch: jest.fn(),
+    reloadProjects: jest.fn(),
     placeholders: [],
     fetching: false,
     hasMore: null,
@@ -302,6 +303,7 @@ describe('CacheLandingPage', function () {
         }),
       ],
       onSearch: jest.fn(),
+      reloadProjects: jest.fn(),
       placeholders: [],
       fetching: false,
       hasMore: null,

Some files were not shown because too many files changed in this diff