Просмотр исходного кода

feat(growth): new onboarding tours for sandbox (#39795)

this pr adds new onboarding tours for the sandbox. these tours are part
of the new sandbox guided tour project.

GRW-675
Richard Roggenkemper 2 лет назад
Родитель
Сommit
63ac78739c

+ 169 - 0
static/app/components/assistant/getGuidesContent.tsx

@@ -6,6 +6,9 @@ import ConfigStore from 'sentry/stores/configStore';
 
 export default function getGuidesContent(orgSlug: string | null): GuidesContent {
   if (ConfigStore.get('demoMode')) {
+    if (localStorage.getItem('new-walkthrough') === '1') {
+      return getDemoModeGuidesV2();
+    }
     return getDemoModeGuides();
   }
   return [
@@ -450,3 +453,169 @@ function getDemoModeGuides(): GuidesContent {
     },
   ];
 }
+
+function getDemoModeGuidesV2(): GuidesContent {
+  return [
+    {
+      guide: 'sidebar_v2',
+      requiredTargets: ['projects', 'issues'],
+      priority: 1,
+      markOthersAsSeen: true,
+      steps: [
+        {
+          title: t('Projects'),
+          target: 'projects',
+          description: t(
+            `Create a project for any type of application you want to monitor.`
+          ),
+        },
+        {
+          title: t('Issues'),
+          target: 'issues',
+          description: t(
+            `Here's a list of what's broken with your application. Sentry automatically groups similar events together into an issue.`
+          ),
+        },
+        {
+          title: t('Performance'),
+          target: 'performance',
+          description: t(
+            `Keep a pulse on crash rates, throughput, and latency issues across projects.`
+          ),
+        },
+        {
+          title: t('Releases'),
+          target: 'releases',
+          description: t(
+            `Track the health of every release, see differences between releases from crash analytics to adoption rates.`
+          ),
+        },
+        {
+          title: t('Discover'),
+          target: 'discover',
+          description: t(
+            `Query and unlock insights into the health of your entire system and get answers to critical business questions all in one place.`
+          ),
+          nextText: t(`Got it`),
+        },
+      ],
+    },
+    {
+      guide: 'issues_v3',
+      requiredTargets: ['tags', 'stack_trace', 'breadcrumbs'],
+      steps: [
+        {
+          title: t('Metadata and metrics'),
+          target: 'tags',
+          description: t(
+            `See tags like specific users affected by the event, device, OS, and browser type.
+            On the right side of the page you can view the number of affected users and exception frequency overtime.`
+          ),
+        },
+        {
+          title: t('Find your broken code'),
+          target: 'stack_trace',
+          description: t(
+            `View the stack trace to see the exact sequence of function calls leading to the error in question.`
+          ),
+        },
+        {
+          title: t('Retrace your steps'),
+          target: 'breadcrumbs',
+          description: t(
+            `Sentry automatically captures breadcrumbs for events so you can see the sequence of events so you can see the sequence of events leading up to the error.`
+          ),
+          nextText: t(`Got it`),
+        },
+      ],
+    },
+    {
+      guide: 'releases_v2',
+      requiredTargets: ['release_projects'],
+      priority: 1,
+      steps: [
+        {
+          title: t('Compare releases'),
+          target: 'release_projects',
+          description: t(
+            `Click here and select the "react-native" project to see how the release is trending compaed to previous releases.`
+          ),
+        },
+      ],
+    },
+    {
+      guide: 'react-native-release',
+      requiredTargets: ['release_version'],
+      steps: [
+        {
+          title: t('Release-specfic trends'),
+          target: 'release_version',
+          description: t(
+            `Select the latest release to review new and regressed issues, and business critical metrics like crash rate, user adoption, and session duration.`
+          ),
+        },
+      ],
+    },
+    {
+      guide: 'release-details_v2',
+      requiredTargets: ['release_states'],
+      steps: [
+        {
+          title: t('New and regresses issues'),
+          target: 'release_states',
+          description: t(
+            `Along with reviewing how your release is trending over time compared to previous releases, you can view new and regressed issues here.`
+          ),
+        },
+      ],
+    },
+    {
+      guide: 'performance',
+      requiredTargets: ['performance_table'],
+      steps: [
+        {
+          title: t('See slow transactions'),
+          target: 'performance_table',
+          description: t(
+            `Trace slow-loading pages back to their API calls, as well as, related errors and users impacted across projects. Select a transaction to see more details.`
+          ),
+        },
+      ],
+    },
+    {
+      guide: 'transaction_summary',
+      requiredTargets: ['user_misery', 'transactions_table'],
+      steps: [
+        {
+          title: t('Identify the root cause'),
+          target: 'user_misery',
+          description: t(
+            'Dive into the details behind a slow transaction. See User Misery, Apdex, and more metrics, along with related events and suspect spans.'
+          ),
+        },
+        {
+          title: t('Breakdown event spans'),
+          target: 'transactions_table',
+          description: t(
+            'Select an Event ID from a list of slow transactions to uncover slow spans.'
+          ),
+          nextText: t(`Got it`),
+        },
+      ],
+    },
+    {
+      guide: 'transaction_details_v2',
+      requiredTargets: ['span_tree'],
+      steps: [
+        {
+          title: t('See slow fast'),
+          target: 'span_tree',
+          description: t(
+            `Expand the spans to see span details from start date, end date to the operation. Below you can view breadcrumbs for a play-by-play of what your users
+            did before encountering the performance.`
+          ),
+        },
+      ],
+    },
+  ];
+}

+ 14 - 12
static/app/components/discover/transactionsList.tsx

@@ -247,18 +247,20 @@ class _TransactionsList extends Component<Props> {
             size="xs"
           />
         </Header>
-        <TransactionsTable
-          eventView={eventView}
-          organization={organization}
-          location={location}
-          isLoading={isLoading}
-          tableData={tableData}
-          columnOrder={columnOrder}
-          titles={titles}
-          generateLink={generateLink}
-          handleCellAction={handleCellAction}
-          useAggregateAlias={!useEvents}
-        />
+        <GuideAnchor target="transactions_table" position="top-start">
+          <TransactionsTable
+            eventView={eventView}
+            organization={organization}
+            location={location}
+            isLoading={isLoading}
+            tableData={tableData}
+            columnOrder={columnOrder}
+            titles={titles}
+            generateLink={generateLink}
+            handleCellAction={handleCellAction}
+            useAggregateAlias={!useEvents}
+          />
+        </GuideAnchor>
       </Fragment>
     );
 

+ 5 - 1
static/app/components/events/eventEntries.tsx

@@ -6,6 +6,7 @@ import uniq from 'lodash/uniq';
 
 import {addErrorMessage} from 'sentry/actionCreators/indicator';
 import {Client} from 'sentry/api';
+import GuideAnchor from 'sentry/components/assistant/guideAnchor';
 import ErrorBoundary from 'sentry/components/errorBoundary';
 import EventContexts from 'sentry/components/events/contexts';
 import EventContextSummary from 'sentry/components/events/contextSummary';
@@ -360,7 +361,10 @@ const EventEntries = ({
           />
         ) : (
           (!!(event.tags ?? []).length || hasContext) && (
-            <StyledEventDataSection title={t('Tags')} type="tags">
+            <StyledEventDataSection
+              title={<GuideAnchor target="tags">{t('Tags')}</GuideAnchor>}
+              type="tags"
+            >
               {hasContext && <EventContextSummary event={event} />}
               <EventTags
                 event={event}

+ 15 - 17
static/app/components/events/interfaces/breadcrumbs/index.tsx

@@ -338,11 +338,7 @@ function BreadcrumbsContainer({
   return (
     <EventDataSection
       type={EntryType.BREADCRUMBS}
-      title={
-        <GuideAnchor target="breadcrumbs" position="right">
-          <h3>{t('Breadcrumbs')}</h3>
-        </GuideAnchor>
-      }
+      title={<h3>{t('Breadcrumbs')}</h3>}
       actions={!showReplay ? searchBar : null}
       wrapTitle={false}
       isCentered
@@ -359,18 +355,20 @@ function BreadcrumbsContainer({
         </Fragment>
       ) : null}
       <ErrorBoundary>
-        <Breadcrumbs
-          router={router}
-          route={route}
-          emptyMessage={getEmptyMessage()}
-          breadcrumbs={filteredBySearch}
-          event={event}
-          organization={organization}
-          onSwitchTimeFormat={handleSwitchTimeFormat}
-          displayRelativeTime={displayRelativeTime}
-          searchTerm={searchTerm}
-          relativeTime={relativeTime!} // relativeTime has to be always available, as the last item timestamp is the event created time
-        />
+        <GuideAnchor target="breadcrumbs" position="bottom">
+          <Breadcrumbs
+            router={router}
+            route={route}
+            emptyMessage={getEmptyMessage()}
+            breadcrumbs={filteredBySearch}
+            event={event}
+            organization={organization}
+            onSwitchTimeFormat={handleSwitchTimeFormat}
+            displayRelativeTime={displayRelativeTime}
+            searchTerm={searchTerm}
+            relativeTime={relativeTime!} // relativeTime has to be always available, as the last item timestamp is the event created time
+          />
+        </GuideAnchor>
       </ErrorBoundary>
     </EventDataSection>
   );

+ 4 - 1
static/app/components/events/interfaces/crashContent/stackTrace/content.tsx

@@ -1,6 +1,7 @@
 import {cloneElement, Component} from 'react';
 import styled from '@emotion/styled';
 
+import GuideAnchor from 'sentry/components/assistant/guideAnchor';
 import {t} from 'sentry/locale';
 import {Frame, Organization, PlatformType} from 'sentry/types';
 import {Event} from 'sentry/types/event';
@@ -261,7 +262,9 @@ class Content extends Component<Props, State> {
     return (
       <Wrapper className={className} data-test-id="stack-trace-content">
         <StacktracePlatformIcon platform={platformIcon} />
-        <StyledList data-test-id="frames">{frames}</StyledList>
+        <GuideAnchor target="stack_trace">
+          <StyledList data-test-id="frames">{frames}</StyledList>
+        </GuideAnchor>
       </Wrapper>
     );
   }

+ 48 - 46
static/app/views/performance/table.tsx

@@ -435,52 +435,54 @@ class _Table extends Component<Props, State> {
     const prependColumnWidths = ['max-content'];
 
     return (
-      <div data-test-id="performance-table">
-        <MEPConsumer>
-          {value => {
-            return (
-              <DiscoverQuery
-                eventView={sortedEventView}
-                orgSlug={organization.slug}
-                location={location}
-                setError={error => setError(error?.message)}
-                referrer="api.performance.landing-table"
-                transactionName={transaction}
-                transactionThreshold={transactionThreshold}
-                queryExtras={getMEPQueryParams(value)}
-                useEvents={useEvents}
-              >
-                {({pageLinks, isLoading, tableData}) => (
-                  <Fragment>
-                    <GridEditable
-                      isLoading={isLoading}
-                      data={tableData ? tableData.data : []}
-                      columnOrder={columnOrder}
-                      columnSortBy={columnSortBy}
-                      grid={{
-                        onResizeColumn: this.handleResizeColumn,
-                        renderHeadCell: this.renderHeadCellWithMeta(
-                          tableData?.meta
-                        ) as any,
-                        renderBodyCell: this.renderBodyCellWithData(tableData) as any,
-                        renderPrependColumns: this.renderPrependCellWithData(
-                          tableData
-                        ) as any,
-                        prependColumnWidths,
-                      }}
-                      location={location}
-                    />
-                    <Pagination
-                      pageLinks={pageLinks}
-                      paginationAnalyticsEvent={this.paginationAnalyticsEvent}
-                    />
-                  </Fragment>
-                )}
-              </DiscoverQuery>
-            );
-          }}
-        </MEPConsumer>
-      </div>
+      <GuideAnchor target="performance_table" position="top-start">
+        <div data-test-id="performance-table">
+          <MEPConsumer>
+            {value => {
+              return (
+                <DiscoverQuery
+                  eventView={sortedEventView}
+                  orgSlug={organization.slug}
+                  location={location}
+                  setError={error => setError(error?.message)}
+                  referrer="api.performance.landing-table"
+                  transactionName={transaction}
+                  transactionThreshold={transactionThreshold}
+                  queryExtras={getMEPQueryParams(value)}
+                  useEvents={useEvents}
+                >
+                  {({pageLinks, isLoading, tableData}) => (
+                    <Fragment>
+                      <GridEditable
+                        isLoading={isLoading}
+                        data={tableData ? tableData.data : []}
+                        columnOrder={columnOrder}
+                        columnSortBy={columnSortBy}
+                        grid={{
+                          onResizeColumn: this.handleResizeColumn,
+                          renderHeadCell: this.renderHeadCellWithMeta(
+                            tableData?.meta
+                          ) as any,
+                          renderBodyCell: this.renderBodyCellWithData(tableData) as any,
+                          renderPrependColumns: this.renderPrependCellWithData(
+                            tableData
+                          ) as any,
+                          prependColumnWidths,
+                        }}
+                        location={location}
+                      />
+                      <Pagination
+                        pageLinks={pageLinks}
+                        paginationAnalyticsEvent={this.paginationAnalyticsEvent}
+                      />
+                    </Fragment>
+                  )}
+                </DiscoverQuery>
+              );
+            }}
+          </MEPConsumer>
+        </div>
+      </GuideAnchor>
     );
   }
 }

+ 11 - 8
static/app/views/performance/transactionSummary/transactionOverview/userStats.tsx

@@ -2,6 +2,7 @@ import {Fragment} from 'react';
 import styled from '@emotion/styled';
 import {Location} from 'history';
 
+import GuideAnchor from 'sentry/components/assistant/guideAnchor';
 import {SectionHeading} from 'sentry/components/charts/styles';
 import Link from 'sentry/components/links/link';
 import Placeholder from 'sentry/components/placeholder';
@@ -111,14 +112,16 @@ function UserStats({
           <SidebarSpacer />
         </Fragment>
       )}
-      <SectionHeading>
-        {t('User Misery')}
-        <QuestionTooltip
-          position="top"
-          title={getTermHelp(organization, PERFORMANCE_TERM.USER_MISERY)}
-          size="sm"
-        />
-      </SectionHeading>
+      <GuideAnchor target="user_misery" position="left">
+        <SectionHeading>
+          {t('User Misery')}
+          <QuestionTooltip
+            position="top"
+            title={getTermHelp(organization, PERFORMANCE_TERM.USER_MISERY)}
+            size="sm"
+          />
+        </SectionHeading>
+      </GuideAnchor>
       {userMisery}
       <SidebarSpacer />
     </Fragment>

+ 22 - 14
static/app/views/releases/detail/overview/releaseIssues.tsx

@@ -6,6 +6,7 @@ import isEqual from 'lodash/isEqual';
 import * as qs from 'query-string';
 
 import {Client} from 'sentry/api';
+import GuideAnchor from 'sentry/components/assistant/guideAnchor';
 import Button, {ButtonLabel} from 'sentry/components/button';
 import ButtonBar, {ButtonGrid} from 'sentry/components/buttonBar';
 import GroupList from 'sentry/components/issues/groupList';
@@ -391,20 +392,27 @@ class ReleaseIssues extends Component<Props, State> {
     return (
       <Fragment>
         <ControlsWrapper>
-          <StyledButtonBar active={issuesType} merged>
-            {issuesTypes.map(({value, label, issueCount}) => (
-              <Button
-                key={value}
-                barId={value}
-                size="xs"
-                onClick={() => this.handleIssuesTypeSelection(value)}
-                data-test-id={`filter-${value}`}
-              >
-                {label}
-                <QueryCount count={issueCount} max={99} hideParens hideIfEmpty={false} />
-              </Button>
-            ))}
-          </StyledButtonBar>
+          <GuideAnchor target="release_states">
+            <StyledButtonBar active={issuesType} merged>
+              {issuesTypes.map(({value, label, issueCount}) => (
+                <Button
+                  key={value}
+                  barId={value}
+                  size="xs"
+                  onClick={() => this.handleIssuesTypeSelection(value)}
+                  data-test-id={`filter-${value}`}
+                >
+                  {label}
+                  <QueryCount
+                    count={issueCount}
+                    max={99}
+                    hideParens
+                    hideIfEmpty={false}
+                  />
+                </Button>
+              ))}
+            </StyledButtonBar>
+          </GuideAnchor>
 
           <OpenInButtonBar gap={1}>
             <Button to={this.getIssuesUrl()} size="xs" data-test-id="issues-button">

+ 3 - 1
static/app/views/releases/list/index.tsx

@@ -530,7 +530,9 @@ class ReleasesList extends AsyncView<Props, State> {
             {this.renderHealthCta()}
 
             <ReleasesPageFilterBar condensed>
-              <ProjectPageFilter />
+              <GuideAnchor target="release_projects">
+                <ProjectPageFilter />
+              </GuideAnchor>
               <EnvironmentPageFilter />
               <DatePageFilter
                 alignDropdown="left"

+ 4 - 1
static/app/views/releases/list/releaseCard/index.tsx

@@ -114,7 +114,10 @@ class ReleaseCard extends Component<Props> {
                 query: {project: getReleaseProjectId(release, selection)},
               }}
             >
-              <GuideAnchor disabled={!isTopRelease} target="release_version">
+              <GuideAnchor
+                disabled={!isTopRelease || projectsToShow.length > 1}
+                target="release_version"
+              >
                 <VersionWrapper>
                   <StyledVersion version={version} tooltipRawVersion anchor={false} />
                 </VersionWrapper>