Browse Source

feat(starfish): Add chart to interaction summary page (#56973)

Ash Anand 1 year ago
parent
commit
2bae6fda38

+ 14 - 1
static/app/views/performance/browser/interactionSummary/index.tsx

@@ -7,15 +7,23 @@ import {t} from 'sentry/locale';
 import useOrganization from 'sentry/utils/useOrganization';
 import {normalizeUrl} from 'sentry/utils/withDomainRequired';
 import {PaddedContainer} from 'sentry/views/performance/browser/interactionsLandingPage';
+import {InteractionBreakdownChart} from 'sentry/views/performance/browser/interactionSummary/interactionBreakdownChart';
 import InteractionSampleTable from 'sentry/views/performance/browser/interactionSummary/sampleTable';
 import {getActionName} from 'sentry/views/performance/browser/interactionTable';
-import {useBrowserModuleFilters} from 'sentry/views/performance/browser/useBrowserFilters';
+import {
+  BrowserStarfishFields,
+  useBrowserModuleFilters,
+} from 'sentry/views/performance/browser/useBrowserFilters';
 import {ModulePageProviders} from 'sentry/views/performance/database/modulePageProviders';
 
 function InteractionSummary() {
   const organization = useOrganization();
   const browserFilters = useBrowserModuleFilters();
 
+  const operation = browserFilters?.[BrowserStarfishFields.TRANSACTION_OP] ?? '';
+  const page = browserFilters?.[BrowserStarfishFields.PAGE] ?? '';
+  const element = browserFilters?.[BrowserStarfishFields.COMPONENT] ?? '';
+
   return (
     <ModulePageProviders title={[t('Performance'), t('Interactions')].join(' — ')}>
       <Layout.Header>
@@ -55,6 +63,11 @@ function InteractionSummary() {
               <DatePageFilter alignDropdown="left" />
             </PageFilterBar>
           </PaddedContainer>
+          <InteractionBreakdownChart
+            operation={operation}
+            page={page}
+            element={element}
+          />
           <InteractionSampleTable />
         </Layout.Main>
       </Layout.Body>

+ 48 - 0
static/app/views/performance/browser/interactionSummary/interactionBreakdownChart.tsx

@@ -0,0 +1,48 @@
+import styled from '@emotion/styled';
+
+import {CHART_PALETTE} from 'sentry/constants/chartPalette';
+import {space} from 'sentry/styles/space';
+import {getDurationUnit} from 'sentry/utils/discover/charts';
+import {useInteractionBreakdownTimeseriesQuery} from 'sentry/views/performance/browser/interactionSummary/useInteractionBreakdownTimeseriesQuery';
+import Chart from 'sentry/views/starfish/components/chart';
+
+type Props = {
+  element: string;
+  operation: string;
+  page: string;
+};
+
+export function InteractionBreakdownChart({operation, element, page}: Props) {
+  const {data, isLoading} = useInteractionBreakdownTimeseriesQuery({
+    operation,
+    element,
+    page,
+  });
+
+  return (
+    <ChartContainer>
+      <Chart
+        height={200}
+        data={data}
+        loading={isLoading}
+        utc={false}
+        chartColors={[CHART_PALETTE[0][0]]}
+        durationUnit={getDurationUnit(data)}
+        aggregateOutputFormat="duration"
+        grid={{
+          left: 20,
+          right: 50,
+          top: 30,
+          bottom: 10,
+        }}
+      />
+    </ChartContainer>
+  );
+}
+
+const ChartContainer = styled('div')`
+  flex: 1;
+  border: 1px solid ${p => p.theme.gray200};
+  border-radius: ${p => p.theme.borderRadius};
+  margin-bottom: ${space(4)};
+`;

+ 83 - 0
static/app/views/performance/browser/interactionSummary/useInteractionBreakdownTimeseriesQuery.tsx

@@ -0,0 +1,83 @@
+import {getInterval} from 'sentry/components/charts/utils';
+import {Series} from 'sentry/types/echarts';
+import EventView, {MetaType} from 'sentry/utils/discover/eventView';
+import {
+  DiscoverQueryProps,
+  useGenericDiscoverQuery,
+} from 'sentry/utils/discover/genericDiscoverQuery';
+import {DiscoverDatasets} from 'sentry/utils/discover/types';
+import {MutableSearch} from 'sentry/utils/tokenizeSearch';
+import {useLocation} from 'sentry/utils/useLocation';
+import useOrganization from 'sentry/utils/useOrganization';
+import usePageFilters from 'sentry/utils/usePageFilters';
+
+type Props = {
+  element: string;
+  operation: string;
+  page: string;
+};
+
+export const useInteractionBreakdownTimeseriesQuery = ({
+  operation,
+  element,
+  page,
+}: Props): {data: Series[]; isLoading: boolean} => {
+  const pageFilters = usePageFilters();
+  const location = useLocation();
+  const organization = useOrganization();
+  const search = new MutableSearch(
+    `transaction.op:${operation} transaction:${page} interactionElement:${element}`
+  );
+  const projectTimeSeriesEventView = EventView.fromNewQueryWithPageFilters(
+    {
+      yAxis: [`p75(transaction.duration)`],
+      name: 'Interaction Duration',
+      query: search.formatString(),
+      version: 2,
+      fields: [],
+      interval: getInterval(pageFilters.selection.datetime, 'low'),
+      dataset: DiscoverDatasets.DISCOVER,
+    },
+    pageFilters.selection
+  );
+
+  const result = useGenericDiscoverQuery<
+    {
+      data: any[];
+      meta: MetaType;
+    },
+    DiscoverQueryProps
+  >({
+    route: 'events-stats',
+    eventView: projectTimeSeriesEventView,
+    location,
+    orgSlug: organization.slug,
+    getRequestPayload: () => ({
+      ...projectTimeSeriesEventView.getEventsAPIPayload(location),
+      yAxis: projectTimeSeriesEventView.yAxis,
+      topEvents: projectTimeSeriesEventView.topEvents,
+      excludeOther: 0,
+      partial: 1,
+      orderby: undefined,
+      interval: projectTimeSeriesEventView.interval,
+    }),
+    options: {
+      enabled: pageFilters.isReady,
+      refetchOnWindowFocus: false,
+    },
+  });
+
+  const seriesData: Series = {
+    seriesName: 'p75(duration)',
+    data: [],
+  };
+
+  const transformedData = result?.data?.data.map(data => ({
+    name: data[0] as string,
+    value: data[1][0].count,
+  }));
+
+  seriesData.data = transformedData ?? [];
+
+  return {data: [seriesData], isLoading: result.isLoading};
+};