Browse Source

fix(projects): Disable release health setup buttons when platform is not supported (#72567)

Fixes https://github.com/getsentry/sentry/issues/72560

Consistently displays a disabled setup button when the project platform
does not support release health. Previously, we only did this on the
project list page but not on the project details page.
Malachi Willey 9 months ago
parent
commit
c1e43597df

+ 12 - 1
static/app/views/projectDetail/missingFeatureButtons/missingReleasesButtons.tsx

@@ -1,8 +1,10 @@
 import {Button} from 'sentry/components/button';
 import ButtonBar from 'sentry/components/buttonBar';
 import FeatureTourModal from 'sentry/components/modals/featureTourModal';
+import {releaseHealth} from 'sentry/data/platformCategories';
 import {t} from 'sentry/locale';
 import type {Organization} from 'sentry/types/organization';
+import type {PlatformKey} from 'sentry/types/project';
 import {trackAnalytics} from 'sentry/utils/analytics';
 import {RELEASES_TOUR_STEPS} from 'sentry/views/releases/list/releasesPromo';
 
@@ -12,10 +14,11 @@ const DOCS_HEALTH_URL = 'https://docs.sentry.io/product/releases/health/';
 type Props = {
   organization: Organization;
   health?: boolean;
+  platform?: PlatformKey;
   projectId?: string;
 };
 
-function MissingReleasesButtons({organization, health, projectId}: Props) {
+function MissingReleasesButtons({organization, health, projectId, platform}: Props) {
   function handleTourAdvance(step: number, duration: number) {
     trackAnalytics('project_detail.releases_tour.advance', {
       organization,
@@ -34,6 +37,8 @@ function MissingReleasesButtons({organization, health, projectId}: Props) {
     });
   }
 
+  const setupDisabled = health && platform && !releaseHealth.includes(platform);
+
   return (
     <ButtonBar gap={1}>
       <Button
@@ -41,6 +46,12 @@ function MissingReleasesButtons({organization, health, projectId}: Props) {
         priority="primary"
         external
         href={health ? DOCS_HEALTH_URL : DOCS_URL}
+        disabled={setupDisabled}
+        title={
+          setupDisabled
+            ? t('Release Health is not yet supported on this platform.')
+            : undefined
+        }
       >
         {t('Start Setup')}
       </Button>

+ 1 - 1
static/app/views/projectDetail/projectDetail.tsx

@@ -333,9 +333,9 @@ class ProjectDetail extends DeprecatedAsyncView<Props, State> {
                 <ProjectLatestReleases
                   organization={organization}
                   projectSlug={params.projectId}
-                  projectId={project?.id}
                   location={location}
                   isProjectStabilized={isProjectStabilized}
+                  project={project}
                 />
                 <ProjectQuickLinks
                   organization={organization}

+ 5 - 5
static/app/views/projectDetail/projectLatestReleases.spec.tsx

@@ -37,7 +37,7 @@ describe('ProjectDetail > ProjectLatestReleases', function () {
         organization={organization}
         projectSlug={project.slug}
         location={router.location}
-        projectId={project.slug}
+        project={project}
         isProjectStabilized
       />
     );
@@ -69,7 +69,7 @@ describe('ProjectDetail > ProjectLatestReleases', function () {
         organization={organization}
         projectSlug={project.slug}
         location={router.location}
-        projectId={project.slug}
+        project={project}
         isProjectStabilized
       />
     );
@@ -92,7 +92,7 @@ describe('ProjectDetail > ProjectLatestReleases', function () {
         organization={organization}
         projectSlug={project.slug}
         location={router.location}
-        projectId={project.slug}
+        project={project}
         isProjectStabilized
       />
     );
@@ -116,7 +116,7 @@ describe('ProjectDetail > ProjectLatestReleases', function () {
         location={LocationFixture({
           query: {statsPeriod: '7d', environment: 'staging', somethingBad: 'nope'},
         })}
-        projectId={project.slug}
+        project={project}
         isProjectStabilized
       />
     );
@@ -138,7 +138,7 @@ describe('ProjectDetail > ProjectLatestReleases', function () {
         location={LocationFixture({
           query: {statsPeriod: '7d', environment: 'staging', somethingBad: 'nope'},
         })}
-        projectId={project.slug}
+        project={project}
         isProjectStabilized={false}
       />
     );

+ 15 - 9
static/app/views/projectDetail/projectLatestReleases.tsx

@@ -15,7 +15,7 @@ import {URL_PARAM} from 'sentry/constants/pageFilters';
 import {IconOpen} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
-import type {Organization, Release} from 'sentry/types';
+import type {Organization, Project, Release} from 'sentry/types';
 
 import MissingReleasesButtons from './missingFeatureButtons/missingReleasesButtons';
 import {SectionHeadingLink, SectionHeadingWrapper, SidebarSection} from './styles';
@@ -28,7 +28,7 @@ type Props = DeprecatedAsyncComponent['props'] & {
   location: Location;
   organization: Organization;
   projectSlug: string;
-  projectId?: string;
+  project?: Project;
 };
 
 type State = {
@@ -85,13 +85,13 @@ class ProjectLatestReleases extends DeprecatedAsyncComponent<Props, State> {
    */
   async onLoadAllEndpointsSuccess() {
     const {releases} = this.state;
-    const {organization, projectId, isProjectStabilized} = this.props;
+    const {organization, project, isProjectStabilized} = this.props;
 
     if (!isProjectStabilized) {
       return;
     }
 
-    if ((releases ?? []).length !== 0 || !projectId) {
+    if ((releases ?? []).length !== 0 || !project?.id) {
       this.setState({hasOlderReleases: true});
       return;
     }
@@ -101,7 +101,7 @@ class ProjectLatestReleases extends DeprecatedAsyncComponent<Props, State> {
     const hasOlderReleases = await fetchAnyReleaseExistence(
       this.api,
       organization.slug,
-      projectId
+      project.id
     );
 
     this.setState({hasOlderReleases, loading: false});
@@ -123,7 +123,7 @@ class ProjectLatestReleases extends DeprecatedAsyncComponent<Props, State> {
   }
 
   renderReleaseRow = (release: Release) => {
-    const {projectId} = this.props;
+    const {project} = this.props;
     const {lastDeploy, dateCreated} = release;
 
     return (
@@ -133,7 +133,7 @@ class ProjectLatestReleases extends DeprecatedAsyncComponent<Props, State> {
           <StyledVersion
             version={release.version}
             tooltipRawVersion
-            projectId={projectId}
+            projectId={project?.id}
           />
         </TextOverflow>
       </Fragment>
@@ -141,7 +141,7 @@ class ProjectLatestReleases extends DeprecatedAsyncComponent<Props, State> {
   };
 
   renderInnerBody() {
-    const {organization, projectId, isProjectStabilized} = this.props;
+    const {organization, project, isProjectStabilized} = this.props;
     const {loading, releases, hasOlderReleases} = this.state;
     const checkingForOlderReleases =
       !(releases ?? []).length && hasOlderReleases === undefined;
@@ -153,7 +153,13 @@ class ProjectLatestReleases extends DeprecatedAsyncComponent<Props, State> {
     }
 
     if (!hasOlderReleases) {
-      return <MissingReleasesButtons organization={organization} projectId={projectId} />;
+      return (
+        <MissingReleasesButtons
+          organization={organization}
+          projectId={project?.id}
+          platform={project?.platform}
+        />
+      );
     }
 
     if (!releases || releases.length === 0) {

+ 2 - 0
static/app/views/projectDetail/projectScoreCards/projectScoreCards.tsx

@@ -40,6 +40,7 @@ function ProjectScoreCards({
         hasSessions={hasSessions}
         query={query}
         field={SessionFieldWithOperation.CRASH_FREE_RATE_SESSIONS}
+        project={project}
       />
 
       <ProjectStabilityScoreCard
@@ -48,6 +49,7 @@ function ProjectScoreCards({
         hasSessions={hasSessions}
         query={query}
         field={SessionFieldWithOperation.CRASH_FREE_RATE_USERS}
+        project={project}
       />
 
       <ProjectVelocityScoreCard

+ 9 - 1
static/app/views/projectDetail/projectScoreCards/projectStabilityScoreCard.tsx

@@ -12,6 +12,7 @@ import {IconArrow} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import type {PageFilters, SessionApiResponse} from 'sentry/types';
 import {SessionFieldWithOperation} from 'sentry/types';
+import type {Project} from 'sentry/types/project';
 import {defined} from 'sentry/utils';
 import {getPeriod} from 'sentry/utils/duration/getPeriod';
 import {formatAbbreviatedNumber} from 'sentry/utils/formatters';
@@ -32,6 +33,7 @@ type Props = {
   hasSessions: boolean | null;
   isProjectStabilized: boolean;
   selection: PageFilters;
+  project?: Project;
   query?: string;
 };
 
@@ -149,7 +151,13 @@ function ProjectStabilityScoreCard(props: Props) {
       <ScoreCard
         title={cardTitle}
         help={cardHelp}
-        score={<MissingReleasesButtons organization={organization} health />}
+        score={
+          <MissingReleasesButtons
+            organization={organization}
+            health
+            platform={props.project?.platform}
+          />
+        }
       />
     );
   }

+ 5 - 26
static/app/views/projectsDashboard/projectCard.tsx

@@ -18,7 +18,6 @@ import ScoreCard, {
   Title,
   Trend,
 } from 'sentry/components/scoreCard';
-import {releaseHealth} from 'sentry/data/platformCategories';
 import {IconArrow, IconSettings} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import ProjectsStatsStore from 'sentry/stores/projectsStatsStore';
@@ -81,26 +80,15 @@ class ProjectCard extends Component<Props> {
 
   renderMissingFeatureCard() {
     const {organization, project} = this.props;
-    if (project.platform && releaseHealth.includes(project.platform)) {
-      return (
-        <ScoreCard
-          title={t('Crash Free Sessions')}
-          score={<MissingReleasesButtons organization={organization} health />}
-        />
-      );
-    }
-
     return (
       <ScoreCard
         title={t('Crash Free Sessions')}
         score={
-          <NotAvailable>
-            {t('Not Available')}
-            <QuestionTooltip
-              title={t('Release Health is not yet supported on this platform.')}
-              size="xs"
-            />
-          </NotAvailable>
+          <MissingReleasesButtons
+            organization={organization}
+            health
+            platform={project.platform}
+          />
         }
       />
     );
@@ -462,15 +450,6 @@ const TransactionsLink = styled(Link)`
   }
 `;
 
-const NotAvailable = styled('div')`
-  font-size: ${p => p.theme.fontSizeMedium};
-  font-weight: ${p => p.theme.fontWeightNormal};
-  display: grid;
-  grid-template-columns: auto auto;
-  gap: ${space(0.5)};
-  align-items: center;
-`;
-
 const SummaryLinkPlaceholder = styled(Placeholder)`
   height: 15px;
   width: 180px;