Browse Source

feat(profiling): add feedback button to all layouts (#59846)

Adds give feedback button to top right corner of all profiling pages
Jonas 1 year ago
parent
commit
4428234916

+ 10 - 2
static/app/components/profiling/profileHeader.tsx

@@ -7,6 +7,7 @@ import {
   ProfilingBreadcrumbs,
   ProfilingBreadcrumbsProps,
 } from 'sentry/components/profiling/profilingBreadcrumbs';
+import ProfilingFeedbackButton from 'sentry/components/profiling/profilingFeedbackButton';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
 import {Event} from 'sentry/types';
@@ -85,17 +86,24 @@ function ProfileHeader({transaction, projectId, eventId}: ProfileHeaderProps) {
           <ProfilingBreadcrumbs organization={organization} trails={breadcrumbTrails} />
         </SmallerProfilingBreadcrumbsWrapper>
       </SmallerHeaderContent>
-      <Layout.HeaderActions>
+      <StyledHeaderActions>
+        <ProfilingFeedbackButton />
         {transactionTarget && (
           <Button size="sm" onClick={handleGoToTransaction} to={transactionTarget}>
             {t('Go to Transaction')}
           </Button>
         )}
-      </Layout.HeaderActions>
+      </StyledHeaderActions>
     </SmallerLayoutHeader>
   );
 }
 
+const StyledHeaderActions = styled(Layout.HeaderActions)`
+  display: flex;
+  flex-direction: row;
+  gap: ${space(1)};
+`;
+
 const SmallerHeaderContent = styled(Layout.HeaderContent)`
   margin-bottom: ${space(1.5)};
 `;

+ 48 - 0
static/app/components/profiling/profilingFeedbackButton.tsx

@@ -0,0 +1,48 @@
+import {useEffect, useRef} from 'react';
+import {BrowserClient, getCurrentHub} from '@sentry/react';
+import {Feedback} from '@sentry-internal/feedback';
+
+import {Button} from 'sentry/components/button';
+import {IconMegaphone} from 'sentry/icons/iconMegaphone';
+import {t} from 'sentry/locale';
+import ConfigStore from 'sentry/stores/configStore';
+import {useLegacyStore} from 'sentry/stores/useLegacyStore';
+
+function ProfilingFeedbackButton() {
+  const buttonRef = useRef<HTMLButtonElement | null>(null);
+  const config = useLegacyStore(ConfigStore);
+  const hub = getCurrentHub();
+  const client = hub.getClient<BrowserClient>();
+  const feedback = client?.getIntegration(Feedback);
+
+  useEffect(() => {
+    if (!buttonRef.current || !feedback) {
+      return undefined;
+    }
+
+    const widget = feedback.attachTo(buttonRef.current, {
+      colorScheme: config.theme === 'dark' ? 'dark' : 'light',
+      formTitle: t('Give Feedback'),
+      submitButtonLabel: t('Send Feedback'),
+      messagePlaceholder: t('What did you expect?'),
+    });
+
+    return () => {
+      if (widget && feedback) {
+        feedback.removeWidget(widget);
+      }
+    };
+  }, [feedback, config.theme]);
+
+  if (!feedback) {
+    return null;
+  }
+
+  return (
+    <Button ref={buttonRef} data-feedback="profiling" size="sm" icon={<IconMegaphone />}>
+      {t('Give Feedback')}
+    </Button>
+  );
+}
+
+export default ProfilingFeedbackButton;

+ 11 - 2
static/app/views/profiling/content.tsx

@@ -20,6 +20,7 @@ import {
   ProfilingUpgradeButton,
 } from 'sentry/components/profiling/billing/alerts';
 import {ProfileEventsTable} from 'sentry/components/profiling/profileEventsTable';
+import ProfilingFeedbackButton from 'sentry/components/profiling/profilingFeedbackButton';
 import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
 import {SidebarPanelKey} from 'sentry/components/sidebar/types';
 import SmartSearchBar, {SmartSearchBarProps} from 'sentry/components/smartSearchBar';
@@ -164,7 +165,7 @@ function ProfilingContent({location}: ProfilingContentProps) {
         <Layout.Page>
           <ProfilingBetaAlertBanner organization={organization} />
           <Layout.Header>
-            <Layout.HeaderContent>
+            <StyledHeaderContent>
               <Layout.Title>
                 {t('Profiling')}
                 <PageHeadingQuestionTooltip
@@ -174,7 +175,8 @@ function ProfilingContent({location}: ProfilingContentProps) {
                   )}
                 />
               </Layout.Title>
-            </Layout.HeaderContent>
+              <ProfilingFeedbackButton />
+            </StyledHeaderContent>
           </Layout.Header>
           <Layout.Body>
             <Layout.Main fullWidth>
@@ -328,6 +330,13 @@ const ALL_FIELDS = [...BASE_FIELDS, 'user_misery()'] as const;
 
 type FieldType = (typeof ALL_FIELDS)[number];
 
+const StyledHeaderContent = styled(Layout.HeaderContent)`
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  flex-direction: row;
+`;
+
 const ActionBar = styled('div')`
   display: grid;
   gap: ${space(2)};

+ 3 - 1
static/app/views/profiling/index.tsx

@@ -5,6 +5,8 @@ import NoProjectMessage from 'sentry/components/noProjectMessage';
 import {t} from 'sentry/locale';
 import useOrganization from 'sentry/utils/useOrganization';
 
+const profilingFeature = ['profiling'];
+
 type Props = {
   children: React.ReactNode;
 };
@@ -15,7 +17,7 @@ function ProfilingContainer({children}: Props) {
   return (
     <Feature
       hookName="feature-disabled:profiling-page"
-      features={['profiling']}
+      features={profilingFeature}
       organization={organization}
       renderDisabled={() => (
         <Layout.Page withPadding>

+ 11 - 2
static/app/views/profiling/profileSummary/index.tsx

@@ -26,6 +26,7 @@ import {
   ProfilingBreadcrumbs,
   ProfilingBreadcrumbsProps,
 } from 'sentry/components/profiling/profilingBreadcrumbs';
+import ProfilingFeedbackButton from 'sentry/components/profiling/profilingFeedbackButton';
 import {SegmentedControl} from 'sentry/components/segmentedControl';
 import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
 import type {SmartSearchBarProps} from 'sentry/components/smartSearchBar';
@@ -154,11 +155,12 @@ function ProfileSummaryHeader(props: ProfileSummaryHeaderProps) {
         </Layout.Title>
       </ProfilingHeaderContent>
       {transactionSummaryTarget && (
-        <Layout.HeaderActions>
+        <StyledHeaderActions>
+          <ProfilingFeedbackButton />
           <LinkButton to={transactionSummaryTarget} size="sm">
             {t('View Transaction Summary')}
           </LinkButton>
-        </Layout.HeaderActions>
+        </StyledHeaderActions>
       )}
       <Tabs onChange={props.onViewChange} value={props.view}>
         <TabList hideBorder>
@@ -181,6 +183,13 @@ const ProfilingHeaderContent = styled(Layout.HeaderContent)`
     line-height: normal;
   }
 `;
+
+const StyledHeaderActions = styled(Layout.HeaderActions)`
+  display: flex;
+  flex-direction: row;
+  gap: ${space(1)};
+`;
+
 const ProfilingTitleContainer = styled('div')`
   display: flex;
   align-items: center;