Browse Source

ref(ddm): Use hasCustomMetrics flag (#62532)

- fixes JAVASCRIPT-2QGS
ArthurKnaus 1 year ago
parent
commit
9d2797309e

+ 1 - 0
fixtures/js-stubs/project.tsx

@@ -29,6 +29,7 @@ export function Project(params: Partial<TProject> = {}): TProject {
     firstTransactionEvent: false,
     groupingAutoUpdate: false,
     groupingConfig: '',
+    hasCustomMetrics: false,
     hasFeedbacks: false,
     hasNewFeedbacks: false,
     hasMinifiedStackTrace: false,

+ 1 - 0
static/app/types/project.tsx

@@ -29,6 +29,7 @@ export type Project = {
   groupingAutoUpdate: boolean;
   groupingConfig: string;
   hasAccess: boolean;
+  hasCustomMetrics: boolean;
   hasFeedbacks: boolean;
   hasMinifiedStackTrace: boolean;
   hasNewFeedbacks: boolean;

+ 0 - 16
static/app/views/ddm/context.tsx

@@ -16,7 +16,6 @@ import {
   useInstantRef,
   useUpdateQuery,
 } from 'sentry/utils/metrics';
-import {parseMRI} from 'sentry/utils/metrics/mri';
 import {useMetricsMeta} from 'sentry/utils/metrics/useMetricsMeta';
 import {decodeList} from 'sentry/utils/queryString';
 import usePageFilters from 'sentry/utils/usePageFilters';
@@ -31,7 +30,6 @@ interface DDMContextValue {
   addWidgets: (widgets: Partial<MetricWidgetQueryParams>[]) => void;
   duplicateWidget: (index: number) => void;
   focusArea: FocusArea | null;
-  hasCustomMetrics: boolean;
   isLoading: boolean;
   metricsMeta: ReturnType<typeof useMetricsMeta>['data'];
   removeFocusArea: () => void;
@@ -54,7 +52,6 @@ export const DDMContext = createContext<DDMContextValue>({
   duplicateWidget: () => {},
   widgets: [],
   metricsMeta: [],
-  hasCustomMetrics: false,
   isLoading: false,
   focusArea: null,
 });
@@ -183,19 +180,8 @@ export function DDMContextProvider({children}: {children: React.ReactNode}) {
   const [focusArea, setFocusArea] = useState<FocusArea | null>(null);
 
   const pageFilters = usePageFilters().selection;
-
   const {data: metricsMeta, isLoading} = useMetricsMeta(pageFilters.projects);
 
-  // TODO(telemetry-experience): Switch to the logic below once we have the hasCustomMetrics flag on project
-  // const {projects} = useProjects();
-  // const selectedProjects = projects.filter(project =>
-  //   pageFilters.projects.includes(parseInt(project.id, 10))
-  // );
-  // const hasCustomMetrics = selectedProjects.some(project => project.hasCustomMetrics);
-  const hasCustomMetrics = !!metricsMeta.find(
-    meta => parseMRI(meta)?.useCase === 'custom'
-  );
-
   const handleAddFocusArea = useCallback(
     (area: FocusArea) => {
       Sentry.metrics.increment('ddm.enhance.add');
@@ -258,7 +244,6 @@ export function DDMContextProvider({children}: {children: React.ReactNode}) {
       removeWidget,
       duplicateWidget: handleDuplicate,
       widgets,
-      hasCustomMetrics,
       isLoading,
       metricsMeta,
       focusArea,
@@ -271,7 +256,6 @@ export function DDMContextProvider({children}: {children: React.ReactNode}) {
       handleDuplicate,
       handleUpdateWidget,
       removeWidget,
-      hasCustomMetrics,
       isLoading,
       metricsMeta,
       selectedWidgetIndex,

+ 2 - 2
static/app/views/ddm/layout.tsx

@@ -34,7 +34,7 @@ import {WidgetDetails} from 'sentry/views/ddm/widgetDetails';
 
 export const DDMLayout = memo(() => {
   const organization = useOrganization();
-  const {metricsMeta, hasCustomMetrics, isLoading} = useDDMContext();
+  const {metricsMeta, isLoading} = useDDMContext();
   const {isLoading: isLoadingScratchpads} = useScratchpads();
   const hasMetrics = !isLoading && metricsMeta.length > 0;
   const {activateSidebar} = useMetricsOnboardingSidebar();
@@ -67,7 +67,7 @@ export const DDMLayout = memo(() => {
         </Layout.HeaderContent>
         <Layout.HeaderActions>
           <ButtonBar gap={1}>
-            {hasMetrics && !hasCustomMetrics && (
+            {hasMetrics && (
               <Button
                 priority="primary"
                 onClick={() => addCustomMetric('header')}

+ 29 - 39
static/app/views/ddm/scratchpadContext.tsx

@@ -14,6 +14,7 @@ import {useClearQuery, useInstantRef, useUpdateQuery} from 'sentry/utils/metrics
 import {useLocalStorageState} from 'sentry/utils/useLocalStorageState';
 import useOrganization from 'sentry/utils/useOrganization';
 import usePageFilters from 'sentry/utils/usePageFilters';
+import usePrevious from 'sentry/utils/usePrevious';
 import useRouter from 'sentry/utils/useRouter';
 
 type Scratchpad = {
@@ -33,17 +34,24 @@ function makeLocalStorageKey(orgSlug: string) {
 
 const EMPTY_QUERY = {};
 
-const useSelectedScratchpad = () => {
+function useScratchpadUrlSync() {
   const {slug} = useOrganization();
-  const [state] = useLocalStorageState<ScratchpadState>(makeLocalStorageKey(slug), {
-    default: null,
-    scratchpads: {},
-  });
-
   const router = useRouter();
-  const routerQuery = router.location.query ?? EMPTY_QUERY;
+  const updateQuery = useUpdateQuery();
+  const clearQuery = useClearQuery();
   const {projects} = usePageFilters().selection;
 
+  const [state, setState] = useLocalStorageState<ScratchpadState>(
+    makeLocalStorageKey(slug),
+    {
+      default: null,
+      scratchpads: {},
+    }
+  );
+  const stateRef = useInstantRef(state);
+  const routerQuery = router.location.query ?? EMPTY_QUERY;
+  const routerQueryRef = useInstantRef(routerQuery);
+
   const [selected, setSelected] = useState<string | null | undefined>(() => {
     if (
       (state.default && !routerQuery.widgets) ||
@@ -65,36 +73,6 @@ const useSelectedScratchpad = () => {
       projects
     );
 
-  return {
-    selected,
-    setSelected,
-    isLoading,
-    projects,
-    savedProjects,
-  };
-};
-
-function useScratchpadUrlSync() {
-  const {slug} = useOrganization();
-  const router = useRouter();
-  const updateQuery = useUpdateQuery();
-  const clearQuery = useClearQuery();
-  const {projects} = usePageFilters().selection;
-
-  const [state, setState] = useLocalStorageState<ScratchpadState>(
-    makeLocalStorageKey(slug),
-    {
-      default: null,
-      scratchpads: {},
-    }
-  );
-  const stateRef = useInstantRef(state);
-  const routerQuery = router.location.query ?? EMPTY_QUERY;
-  const routerQueryRef = useInstantRef(routerQuery);
-
-  const {selected, setSelected, isLoading} = useSelectedScratchpad();
-  const selectedQuery = selected && state.scratchpads[selected].query;
-
   const toggleSelected = useCallback(
     (id: string | null) => {
       if (id === selected) {
@@ -164,6 +142,7 @@ function useScratchpadUrlSync() {
 
   // Changes the query when a scratchpad is selected, clears it when none is selected
   useEffect(() => {
+    const selectedQuery = selected && stateRef.current.scratchpads[selected].query;
     if (selectedQuery && !isEqual(selectedQuery, routerQueryRef.current)) {
       // If the selected scratchpad has a start and end date, remove the statsPeriod
       if (selectedQuery.start && selectedQuery.end) {
@@ -176,14 +155,25 @@ function useScratchpadUrlSync() {
     } else if (selectedQuery === null) {
       clearQuery();
     }
-  }, [clearQuery, updateQuery, selectedQuery, routerQueryRef]);
+  }, [clearQuery, updateQuery, selected, routerQueryRef, stateRef]);
 
+  const previousSelected = usePrevious(selected);
   // Saves all URL changes to the selected scratchpad to local storage
   useEffect(() => {
+    const selectedQuery = selected && stateRef.current.scratchpads[selected].query;
+    // normal update path
     if (selected && !isEmpty(routerQuery) && !isLoading) {
       update(selected, routerQuery);
+      // project selection changes should ignore loading state
+    } else if (
+      selectedQuery &&
+      isLoading &&
+      selected === previousSelected &&
+      routerQuery.project !== selectedQuery.project
+    ) {
+      update(selected, routerQuery);
     }
-  }, [routerQuery, projects, isLoading, selected, update]);
+  }, [routerQuery, projects, selected, update, isLoading, stateRef, previousSelected]);
 
   return useMemo(
     () => ({

+ 9 - 9
static/app/views/ddm/scratchpadSelector.tsx

@@ -30,19 +30,19 @@ export function ScratchpadSelector() {
 
   const isDefault = useCallback(
     scratchpad => scratchpads.default === scratchpad.id,
-    [scratchpads]
+    [scratchpads.default]
   );
 
   const scratchpadOptions = useMemo(
     () =>
-      Object.values(scratchpads.all).map((s: any) => ({
-        value: s.id,
-        label: s.name,
+      Object.values(scratchpads.all).map(scratchpad => ({
+        value: scratchpad.id,
+        label: scratchpad.name,
         trailingItems: (
           <Fragment>
             <Tooltip
               title={
-                isDefault(s)
+                isDefault(scratchpad)
                   ? t('Remove as default scratchpad')
                   : t('Set as default scratchpad')
               }
@@ -57,15 +57,15 @@ export function ScratchpadSelector() {
                   });
                   Sentry.metrics.increment('ddm.scratchpad.set_default');
 
-                  if (isDefault(s)) {
+                  if (isDefault(scratchpad)) {
                     scratchpads.setDefault(null);
                   } else {
-                    scratchpads.setDefault(s.id ?? null);
+                    scratchpads.setDefault(scratchpad.id ?? null);
                   }
                 }}
               >
                 <StyledDropdownIcon>
-                  <IconBookmark isSolid={isDefault(s)} />
+                  <IconBookmark isSolid={isDefault(scratchpad)} />
                 </StyledDropdownIcon>
               </Button>
             </Tooltip>
@@ -82,7 +82,7 @@ export function ScratchpadSelector() {
                       });
                       Sentry.metrics.increment('ddm.scratchpad.remove');
 
-                      return scratchpads.remove(s.id);
+                      scratchpads.remove(scratchpad.id);
                     },
                     message: t('Are you sure you want to delete this scratchpad?'),
                     confirmText: t('Delete'),