Browse Source

feat(bug reports): fetch event data for feedback issues (#58530)

For each issue, fetch the latest event. Displayed as raw data for now

<img width="611" alt="SCR-20231020-kluu"
src="https://github.com/getsentry/sentry/assets/56095982/0c173956-e904-4b6a-9d63-ee5d7d03e5a0">
Michelle Zhang 1 year ago
parent
commit
d664830f51

+ 14 - 2
static/app/components/feedback/feedbackItem/feedbackItem.tsx

@@ -16,15 +16,17 @@ import TextCopyInput from 'sentry/components/textCopyInput';
 import {IconChevron, IconEllipsis, IconJson, IconLink} from 'sentry/icons';
 import {IconChevron, IconEllipsis, IconJson, IconLink} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
 import {space} from 'sentry/styles/space';
+import {Event} from 'sentry/types';
 import {getShortEventId} from 'sentry/utils/events';
 import {getShortEventId} from 'sentry/utils/events';
 import type {HydratedFeedbackItem} from 'sentry/utils/feedback/item/types';
 import type {HydratedFeedbackItem} from 'sentry/utils/feedback/item/types';
 import useOrganization from 'sentry/utils/useOrganization';
 import useOrganization from 'sentry/utils/useOrganization';
 
 
 interface Props {
 interface Props {
+  eventData: Event | undefined;
   feedbackItem: HydratedFeedbackItem;
   feedbackItem: HydratedFeedbackItem;
 }
 }
 
 
-export default function FeedbackItem({feedbackItem}: Props) {
+export default function FeedbackItem({feedbackItem, eventData}: Props) {
   const organization = useOrganization();
   const organization = useOrganization();
 
 
   return (
   return (
@@ -129,7 +131,7 @@ export default function FeedbackItem({feedbackItem}: Props) {
 
 
         {/* <TagsSection tags={feedbackItem.tags} /> */}
         {/* <TagsSection tags={feedbackItem.tags} /> */}
 
 
-        <Section icon={<IconJson size="xs" />} title={t('Raw')}>
+        <Section icon={<IconJson size="xs" />} title={t('Raw Issue Data')}>
           <ObjectInspector
           <ObjectInspector
             data={feedbackItem}
             data={feedbackItem}
             expandLevel={3}
             expandLevel={3}
@@ -139,6 +141,16 @@ export default function FeedbackItem({feedbackItem}: Props) {
             }}
             }}
           />
           />
         </Section>
         </Section>
+        <Section icon={<IconJson size="xs" />} title={t('Raw Event Data')}>
+          <ObjectInspector
+            data={eventData}
+            expandLevel={3}
+            theme={{
+              TREENODE_FONT_SIZE: '0.7rem',
+              ARROW_FONT_SIZE: '0.5rem',
+            }}
+          />
+        </Section>
       </OverflowPanelItem>
       </OverflowPanelItem>
     </Fragment>
     </Fragment>
   );
   );

+ 3 - 2
static/app/components/feedback/feedbackItem/feedbackItemLoader.tsx

@@ -16,7 +16,8 @@ export default function FeedbackItemLoader({feedbackSlug}: Props) {
   const {
   const {
     isLoading: isIssueLoading,
     isLoading: isIssueLoading,
     isError: isIssueError,
     isError: isIssueError,
-    data: issue,
+    issueData: issue,
+    eventData: event,
   } = useFetchFeedbackIssue({feedbackId, organization});
   } = useFetchFeedbackIssue({feedbackId, organization});
 
 
   return isIssueLoading || !issue ? (
   return isIssueLoading || !issue ? (
@@ -24,6 +25,6 @@ export default function FeedbackItemLoader({feedbackSlug}: Props) {
   ) : isIssueError ? (
   ) : isIssueError ? (
     <FeedbackErrorDetails error={t('Unable to load feedback')} />
     <FeedbackErrorDetails error={t('Unable to load feedback')} />
   ) : (
   ) : (
-    <FeedbackItem feedbackItem={issue} />
+    <FeedbackItem feedbackItem={issue} eventData={event} />
   );
   );
 }
 }

+ 13 - 4
static/app/components/feedback/useFetchFeedbackIssue.tsx

@@ -1,5 +1,5 @@
 import hydrateFeedbackRecord from 'sentry/components/feedback/hydrateFeedbackRecord';
 import hydrateFeedbackRecord from 'sentry/components/feedback/hydrateFeedbackRecord';
-import {Organization} from 'sentry/types';
+import {Event, Organization} from 'sentry/types';
 import {RawFeedbackItemResponse} from 'sentry/utils/feedback/item/types';
 import {RawFeedbackItemResponse} from 'sentry/utils/feedback/item/types';
 import {useApiQuery, type UseApiQueryOptions} from 'sentry/utils/queryClient';
 import {useApiQuery, type UseApiQueryOptions} from 'sentry/utils/queryClient';
 
 
@@ -12,7 +12,7 @@ export default function useFetchFeedbackIssue(
   {feedbackId, organization}: Props,
   {feedbackId, organization}: Props,
   options: undefined | Partial<UseApiQueryOptions<RawFeedbackItemResponse>> = {}
   options: undefined | Partial<UseApiQueryOptions<RawFeedbackItemResponse>> = {}
 ) {
 ) {
-  const {data, ...result} = useApiQuery<RawFeedbackItemResponse>(
+  const {data: issueData, ...issueResult} = useApiQuery<RawFeedbackItemResponse>(
     [
     [
       `/organizations/${organization.slug}/issues/${feedbackId}/`,
       `/organizations/${organization.slug}/issues/${feedbackId}/`,
       {
       {
@@ -28,8 +28,17 @@ export default function useFetchFeedbackIssue(
     }
     }
   );
   );
 
 
+  const {data: eventData, ...eventResult} = useApiQuery<Event>(
+    [`/organizations/${organization.slug}/issues/${feedbackId}/events/latest/`],
+    {
+      staleTime: 0,
+    }
+  );
+
   return {
   return {
-    data: data ? hydrateFeedbackRecord(data) : undefined,
-    ...result,
+    issueData: issueData ? hydrateFeedbackRecord(issueData) : undefined,
+    eventData,
+    eventResult,
+    ...issueResult,
   };
   };
 }
 }