Browse Source

feat(functions): Make sure to reset cursor for profiling widgets (#52458)

When changing the project/env/datetime/widget, the cursor should be
reset to ensure that the newly loaded widget is on the first page.
Tony Xiao 1 year ago
parent
commit
31ea6326a6

+ 12 - 3
static/app/views/profiling/content.tsx

@@ -46,6 +46,10 @@ import {ProfilesChartWidget} from './landing/profilesChartWidget';
 import {ProfilingSlowestTransactionsPanel} from './landing/profilingSlowestTransactionsPanel';
 import {ProfilingOnboardingPanel} from './profilingOnboardingPanel';
 
+const LEFT_WIDGET_CURSOR = 'leftCursor';
+const RIGHT_WIDGET_CURSOR = 'rightCursor';
+const CURSOR_PARAMS = [LEFT_WIDGET_CURSOR, RIGHT_WIDGET_CURSOR];
+
 interface ProfilingContentProps {
   location: Location;
 }
@@ -189,9 +193,12 @@ function ProfilingContent({location}: ProfilingContentProps) {
               )}
               <ActionBar>
                 <PageFilterBar condensed>
-                  <ProjectPageFilter />
-                  <EnvironmentPageFilter />
-                  <DatePageFilter alignDropdown="left" />
+                  <ProjectPageFilter resetParamsOnChange={CURSOR_PARAMS} />
+                  <EnvironmentPageFilter resetParamsOnChange={CURSOR_PARAMS} />
+                  <DatePageFilter
+                    alignDropdown="left"
+                    resetParamsOnChange={CURSOR_PARAMS}
+                  />
                 </PageFilterBar>
                 {profilingUsingTransactions ? (
                   <SearchBar
@@ -274,12 +281,14 @@ function ProfilingContent({location}: ProfilingContentProps) {
                       />
                       <WidgetsContainer>
                         <LandingWidgetSelector
+                          cursorName={LEFT_WIDGET_CURSOR}
                           widgetHeight="340px"
                           defaultWidget="slowest functions"
                           query={query}
                           storageKey="profiling-landing-widget-0"
                         />
                         <LandingWidgetSelector
+                          cursorName={RIGHT_WIDGET_CURSOR}
                           widgetHeight="340px"
                           defaultWidget="regressed functions"
                           query={query}

+ 14 - 9
static/app/views/profiling/landing/functionTrendsWidget.tsx

@@ -43,17 +43,19 @@ import {
 } from './styles';
 
 const MAX_FUNCTIONS = 3;
-const CURSOR_NAME = 'fnTrendCursor';
+const DEFAULT_CURSOR_NAME = 'fnTrendCursor';
 
 interface FunctionTrendsWidgetProps {
   trendFunction: 'p50()' | 'p75()' | 'p95()' | 'p99()';
   trendType: TrendType;
+  cursorName?: string;
   header?: ReactNode;
   userQuery?: string;
   widgetHeight?: string;
 }
 
 export function FunctionTrendsWidget({
+  cursorName = DEFAULT_CURSOR_NAME,
   header,
   trendFunction,
   trendType,
@@ -65,16 +67,19 @@ export function FunctionTrendsWidget({
   const [expandedIndex, setExpandedIndex] = useState(0);
 
   const fnTrendCursor = useMemo(
-    () => decodeScalar(location.query[CURSOR_NAME]),
-    [location.query]
+    () => decodeScalar(location.query[cursorName]),
+    [cursorName, location.query]
   );
 
-  const handleCursor = useCallback((cursor, pathname, query) => {
-    browserHistory.push({
-      pathname,
-      query: {...query, [CURSOR_NAME]: cursor},
-    });
-  }, []);
+  const handleCursor = useCallback(
+    (cursor, pathname, query) => {
+      browserHistory.push({
+        pathname,
+        query: {...query, [cursorName]: cursor},
+      });
+    },
+    [cursorName]
+  );
 
   const trendsQuery = useProfileFunctionTrends({
     trendFunction,

+ 23 - 2
static/app/views/profiling/landing/landingWidgetSelector.tsx

@@ -1,8 +1,10 @@
-import {useMemo} from 'react';
+import {useCallback, useMemo} from 'react';
+import omit from 'lodash/omit';
 
 import {CompactSelect, SelectOption} from 'sentry/components/compactSelect';
 import {t} from 'sentry/locale';
 import {MutableSearch} from 'sentry/utils/tokenizeSearch';
+import useRouter from 'sentry/utils/useRouter';
 import {useSyncedLocalStorageState} from 'sentry/utils/useSyncedLocalStorageState';
 
 import {FunctionTrendsWidget} from './functionTrendsWidget';
@@ -14,6 +16,7 @@ export type WidgetOption =
   | 'improved functions';
 
 interface LandingWidgetSelectorProps {
+  cursorName: string;
   defaultWidget: WidgetOption;
   query: string;
   storageKey: string;
@@ -21,15 +24,30 @@ interface LandingWidgetSelectorProps {
 }
 
 export function LandingWidgetSelector({
+  cursorName,
   defaultWidget,
   storageKey,
   widgetHeight,
 }: LandingWidgetSelectorProps) {
+  const router = useRouter();
+
   const [selectedWidget, setSelectedWidget] = useSyncedLocalStorageState<WidgetOption>(
     storageKey,
     defaultWidget
   );
 
+  const onWidgetChange = useCallback(
+    opt => {
+      const newQuery = omit(router.location.query, [cursorName]);
+      router.push({
+        pathname: router.location.pathname,
+        query: newQuery,
+      });
+      setSelectedWidget(opt.value);
+    },
+    [cursorName, router, setSelectedWidget]
+  );
+
   const functionQuery = useMemo(() => {
     const conditions = new MutableSearch('');
     conditions.setFilterValues('is_application', ['1']);
@@ -40,7 +58,7 @@ export function LandingWidgetSelector({
     <CompactSelect
       value={selectedWidget}
       options={WIDGET_OPTIONS}
-      onChange={opt => setSelectedWidget(opt.value)}
+      onChange={onWidgetChange}
       triggerProps={{borderless: true, size: 'zero'}}
       offset={4}
     />
@@ -50,6 +68,7 @@ export function LandingWidgetSelector({
     case 'slowest functions':
       return (
         <SlowestFunctionsWidget
+          cursorName={cursorName}
           header={header}
           userQuery={functionQuery}
           widgetHeight={widgetHeight}
@@ -58,6 +77,7 @@ export function LandingWidgetSelector({
     case 'regressed functions':
       return (
         <FunctionTrendsWidget
+          cursorName={cursorName}
           header={header}
           trendFunction="p95()"
           trendType="regression"
@@ -68,6 +88,7 @@ export function LandingWidgetSelector({
     case 'improved functions':
       return (
         <FunctionTrendsWidget
+          cursorName={cursorName}
           header={header}
           trendFunction="p95()"
           trendType="improvement"

+ 14 - 9
static/app/views/profiling/landing/slowestFunctionsWidget.tsx

@@ -38,15 +38,17 @@ import {
 } from './styles';
 
 const MAX_FUNCTIONS = 3;
-const CURSOR_NAME = 'slowFnCursor';
+const DEFAULT_CURSOR_NAME = 'slowFnCursor';
 
 interface SlowestFunctionsWidgetProps {
+  cursorName?: string;
   header?: ReactNode;
   userQuery?: string;
   widgetHeight?: string;
 }
 
 export function SlowestFunctionsWidget({
+  cursorName = DEFAULT_CURSOR_NAME,
   header,
   userQuery,
   widgetHeight,
@@ -56,16 +58,19 @@ export function SlowestFunctionsWidget({
   const [expandedIndex, setExpandedIndex] = useState(0);
 
   const slowFnCursor = useMemo(
-    () => decodeScalar(location.query[CURSOR_NAME]),
-    [location.query]
+    () => decodeScalar(location.query[cursorName]),
+    [cursorName, location.query]
   );
 
-  const handleCursor = useCallback((cursor, pathname, query) => {
-    browserHistory.push({
-      pathname,
-      query: {...query, [CURSOR_NAME]: cursor},
-    });
-  }, []);
+  const handleCursor = useCallback(
+    (cursor, pathname, query) => {
+      browserHistory.push({
+        pathname,
+        query: {...query, [cursorName]: cursor},
+      });
+    },
+    [cursorName]
+  );
 
   const functionsQuery = useProfileFunctions<FunctionsField>({
     fields: functionsFields,